工厂与观察者模式

news2024/11/20 9:23:47

工厂模式介绍

通过一个加工厂,在这个工厂中添加对应材料,我们就可以得到想要的东西,在程序设计中,这种模式就叫做工厂模式,工厂生成出的产品就是某个类的实例,也就是对象。

关于工厂模式一共有三种,分别是:简单工厂模式、工厂模式、抽象工厂模式。

简单工厂模式

比如说你要生产一些物品,生产的方法都是一样的只是原材料不同。你可以设计一个基类,提供生产方法。然后将要生产的对象材料加入到生产类中即可。后面可以再定义一个对象工厂类,用来创建对应材料。

创建一个新的类, 可以将这个类称之为工厂类。对于简单工厂模式来说,需要的工厂类只有一个。工厂类中添加一个公共的成员函数,通过这个函数来创建我们需要的对象,通过这个对象调用工厂函数,这样就可以生产出一个指定类型的实例对象了。这里可以使用c++中的多态来完成。

例如:先定义一个基类,将其方法定义为虚函数。

class Product
{
public:
	Product()
	{
	  ;
	}
	virtual void produce()
	{
		cout << "进行生产" << endl;
	}
	 virtual ~Product()
	{
		 cout << "资源释放" << endl;
	}
};

定义要实例化的对象

class Milk :public Product
{
public:
	void produce()
	{
		cout << "生产了牛奶" << endl;
	}
	~Milk()
	{
		cout << "delete Milk" << endl;
	}
};

class Apple :public Product
{
public:
	void product()
	{
		cout << "生产了apple" << endl;
	}
	~Apple()
	{
		cout << "delete apple" << endl;
	}
};

定义物品工厂类,用来生产对应材料

enum class Type :char { milk,apple };
class Factory
{
public:
	Product* p = nullptr;
	Product* create(Type T)
	{
		switch (T)
		{
		case Type::milk:
			p = new Milk;
			break;
		case Type::apple:
			p = new Apple;
			break;
		default:
			break;
		}
		return p;
	}
};
int main()
{

	Factory* f = new Factory;
	Product* p = f->create(Type::milk);//需要生产材料,就对其参数进行修改
	p->produce();
	delete p;
	return 0;
}

caf69a45a766483da2fc2a1fe83f8b3c.png

 工厂类模式

如果要可以生成更多种类的物品,需要添加更多的物品对象,同时还要在工厂函数的switch语句中添加更多的case,很明显这违背了封闭原则。

简单工厂模式是只有一个工厂类,而工厂模式是有很多的工厂类。

 

  1. 一个基类,包含一个虚工厂函数,用于实现多态。
  2. 多个子类,重写父类的工厂函数。每个子工厂类负责生产某种物品,这相当于再次解耦,如果要生产新物品,那么只需要添加对应的工厂类,无需修改原有的代码。

代码:

class Product
{
public:
	
	virtual void produce()
	{
		cout << "进行生产" << endl;
	}
	virtual ~Product()
	{
		cout << "资源释放" << endl;
	}
};

class Milkpro :public Product
{
public:

	void produce()
	{
		cout << "生产了牛奶" << endl;
	}
	~Milkpro()
	{
		cout << "delete Milk" << endl;
	}
};

class Applepro :public Product
{
public:
	
	void product()
	{
		cout << "生产了apple" << endl;
	}
	~Applepro()
	{
		cout << "delete apple" << endl;
	}
};

class Factory//并没有在这个类中直接生产材料,而是定义为抽象类
{
public:
	virtual Product* creat() = 0;
	virtual ~Factory()
	{
		;
	}
};

class Milk :public Factory
{
public:
	
	Product* creat()
	{
		return new Milkpro;
	}
	~Milk()
	{
		cout << "delete Milk" << endl;
	}
};
class Apple :public Factory
{
public:
	Product* creat()
	{
		return new Applepro;
	}
	~Apple()
	{
		cout << "delete Apple" << endl;
	}
};
int main()
{
	Factory* f = new Milk;
	Product* p= f->creat();
	p->produce();
	delete p;
	return 0;	
}

27ba17f099df42d884bec8c171e88f8f.png

 抽象工厂类

假如要生产一艘船,该的组成为:

船体,船的动力系统,船中配备的武器。

船体的选择:木材 合金

动力系统的选择:人力驱动,核反应驱动

武器的选择:枪,自动机关炮

这样一共就有8种选则。

船体,因为船体材料的这个属性是可变的,所以还需要给它提供一个抽象类,在这个抽象类的子类中就可以去更换不同的船体材料。

class ShipBody
{
public:
    virtual string getShipBody() = 0;
    virtual ~ShipBody() {}
};

class WoodBody : public ShipBody
{
public:
    string getShipBody() override
    {
        return string("用<木材>制作轮船船体...");
    }
};

class MetalBody : public ShipBody
{
public:
    string getShipBody() override
    {
        return string("用<合金>制作轮船船体...");
    }
};

动力系统与武器也是一样:

// 动力
class Engine
{
public:
    virtual string getEngine() = 0;
    virtual ~Engine() {}
};

class Human : public Engine
{
public:
    string getEngine() override
    {
        return string("使用<人力驱动>...");
    }
};
class Nuclear : public Engine
{
public:
    string getEngine() override
    {
        return string("使用<核能驱动>...");
    }
};

// 武器
class Weapon
{
public:
    virtual string getWeapon() = 0;
    virtual ~Weapon() {}
};

class Gun : public Weapon
{
public:
    string getWeapon() override
    {
        return string("配备的武器是<枪>");
    }
};

class Cannon : public Weapon
{
public:
    string getWeapon() override
    {
        return string("配备的武器是<自动机关炮>");
    }
};

一首船需要3个组成部分,这里用3个变量来表示:

class Ship
{
public:
    Ship(ShipBody* body, Weapon* weapon, Engine* engine) :
        m_body(body), m_weapon(weapon), m_engine(engine)
    {
    }
    string getProperty()
    {
//      这也是多态实现,获取对应船组成部分的材料
        string info = m_body->getShipBody() + m_weapon->getWeapon() + m_engine->getEngine();
        return info;
    }
    ~Ship()
    {
        delete m_body;
        delete m_engine;
        delete m_weapon;
    }
private:
    ShipBody* m_body = nullptr;
    Weapon* m_weapon = nullptr;
    Engine* m_engine = nullptr;
};

工厂类与上面一样,不直接进行提供船部件,而是定义为抽象类,让子类去提供船的部件。

/ 工厂类
class AbstractFactory
{
public:
    virtual Ship* createShip() = 0;
    virtual ~AbstractFactory() {}
};

class BasicFactory : public AbstractFactory//定义木头,枪,人力的船
{
public:
    Ship* createShip() override
    {
        Ship* ship = new Ship(new WoodBody, new Gun, new Human);
        cout << "<基础型>战船生产完毕, 可以下水啦..." << endl;
        return ship;
    }
};

 结果:

int main()
{
    AbstractFactory* factroy = new BasicFactory;
    Ship* ship = factroy->createShip();
    cout << ship->getProperty();
    delete ship;
    delete factroy;
    return 0;
}

3a2868f99e6b4a99ba5b927555b4d37f.png

对比:

  • 简单工厂模式不能遵守开放-封闭原则,该工厂类没有设置为抽象类,要在该类中直接添加生产对象。
  • 工厂模式创建的对象  对应的类不需要提供抽象类,需要创建什么对象,直接提供对应的子类
  • 抽象工厂模式创建的对象  对应的类有抽象的基类,创建的对象有多种不同的组合方法。

观察者模式

一个简单的例子:交叉路口的红绿灯。过往的车辆就是观察者或则是订阅者,信号灯就是消息的发布者。当车辆到了该路口,车辆就会观测路灯,当路灯为红灯时,车辆即可通行。当车辆远离该路口时,车辆就不需要观察路灯的信号了。

其他例子:购买的商品被送到菜鸟驿站,会收到驿站发送的提示信息。

这里以报刊为例,报刊可以发布多种类型的消息给不同的人。

发布者,需要满足以下的需求:

  • 添加订阅者,将所有的订阅者存储起来
  • 删除订阅者,将其从订阅者列表中删除
  • 将消息发送给订阅者(发通知)

发布者

发布者未必是一种类型的,不同的发布者可以发布不同种类的消息。先创建出一个发布者的抽象类。

class Observer;//订阅者抽象类

class NewsAgency//发布者抽象类
{
public:
    void attach(Observer* ob)
    {
        m_list.push_back(ob);//增加订阅者
    }
    void deatch(Observer* ob)
    {
       m_list.remove(ob);//删除订阅者
    }
    virtual void notify(string msg) = 0;//通知
    virtual ~NewsAgency() {};
protected:
    list<Observer*> m_list;   // 订阅者列表
};

class News_A :public NewsAgency
{
public:
    void notify(string msg) override
    {
        cout << "这是NewA新闻报刊" << endl;
        for (auto ch : m_list)
        {
            ch->update(msg);
        }
    }
};
class News_B :public NewsAgency
{
public:
    void notify(string msg) override
    {
        cout << "这是NewB新闻报刊" << endl;
        for (auto ch : m_list)
        {
            ch->update(msg);
        }
    }
};

订阅者

观察者也未必只是一种对象,给所有的观察者定义一个抽象的基类。

// 抽象的订阅者类
class Observer
{
public:

  //通过构造函数给观察者类提供一个信息的发布者 
    Observer(string name, NewsAgency* news) :m_name(name), m_news(news) 
    {
        m_news->attach(this);//发布者对象将观察者对象存储了起来,可以收到发布的消息
    }
    void unsubscribe()
    {
        m_news->deatch(this);//订阅者取消订阅
    }
    virtual void update(string msg) = 0;
    virtual ~Observer() {}
protected:
    string m_name;
    NewsAgency* m_news;
};

class Observer_A : public Observer//订阅者A
{
public:
    using Observer::Observer;
    void update(string msg) override
    {
        cout << "订阅者A收到新消息: " << msg << endl;
    }
};

class Observer_B : public Observer//订阅者B
{
public:
    using Observer::Observer;
    void update(string msg) override
    {
        cout << "订阅者B收到新消息: " << msg << endl;
    }
};

过程

int main()
{

    News_A* New_a = new News_A;
    News_B* New_b = new News_B;
 
    Observer_A* obser_a = new Observer_A("observer_A",New_a);
    Observer_B* obser_b = new Observer_B("observer_B",New_b);


    New_a->notify("明天会下雨哦*************");
    New_b->notify("明天广场会进行发布会活动,请大家参加");

    return 0;
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1046331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++11】左值引用右值引用,移动构造的使用

&#x1f30f;博客主页&#xff1a; 主页 &#x1f516;系列专栏&#xff1a; C ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ &#x1f60d;期待与大家一起进步&#xff01; 文章目录 一、左值与右值二、 引用总结&#xff1a;1.左值&#xff1a;2.右值&#xff1a; 三、…

微服务调用没有返回值,无法组成对象,但是会有feign的信息

事件起因 还是那个项目&#xff0c;至少对于我来说要学习的东西其实还是挺多的。 需求 员工信息管理&#xff0c;员工简历&#xff0c;导出功能&#xff0c;需要去联查员工的各项信息&#xff0c;其中&#xff0c;涉及到微服务的之间的操作出现了问题&#xff0c;目前主要的…

时空碰撞之当Leaflet遇到Echarts

前言 在之前的博客中&#xff0c;有介绍如何进行Leaflet展示的&#xff0c;也有介绍Echarts如何进行高效图表展示的。针对一些时空类的场景&#xff0c;比如需要跟随GIS地图一起进行图表展示&#xff0c;如何在地图上集成图表插件。本文将以常用的Leaflet为例&#xff0c;重点讲…

JAVA中使用CompletableFuture进行异步编程

JAVA中使用CompletableFuture进行异步编程 1、什么是CompletableFuture CompletableFuture 是 JDK8 提供的 Future 增强类&#xff0c;CompletableFuture 异步任务执行线程池&#xff0c;默认是把异步任 务都放在 ForkJoinPool 中执行。 在这种方式中&#xff0c;主线程不会…

I/O

IO 流简介 IO 即 Input/Output&#xff0c;输入和输出。数据输入到计算机内存的过程即输入&#xff0c;反之输出到外部存储&#xff08;比如数据库&#xff0c;文件&#xff0c;远程主机&#xff09;的过程即输出。IO 流在 Java 中分为输入流和输出流&#xff0c;而根据数据的…

DAY47 多表外键联系

一、表设计之关联关系 外键&#xff1a;主键是用于表示数据的唯一性字段&#xff0c;外键是用于建立关联关系的字段&#xff0c;值通常指向另一张表的主键 一对一 什么是一对一的关系&#xff1a;有A,B两张表&#xff0c;A表中一条数据对应B表中的一条数据&#xff0c;称之为一…

Java 设计模式——抽象工厂模式

目录 1.概念2.结构3.实现4.优缺点5.使用场景6.模式扩展7.JDK源码解析——Collection.iterator方法 1.概念 &#xff08;1&#xff09;Java 设计模式——工厂方法模式中考虑的是一类产品的生产&#xff0c;如畜牧场只养动物、电视机厂只生产电视机等。这些工厂只生产同种类产品…

MATLAB m文件格式化

记录一个网上查到的目前感觉挺好用的格式化方法。 原链接&#xff1a; https://cloud.tencent.com/developer/article/2058259 压缩包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ZpQ9qGLY7sjcvxzjMPAitw?pwd6666 提取码&#xff1a;6666 下载压缩包&#xf…

【GDB】自定义命令

.gdbinit 文件的使用 gdb自定义命令 自定义命令格式 define <command> <code> end document <command> <help text> end示例 .gdbinit 脚本中输入如下内容 layout asm b 5define print-tyustliecho hello, world\n enddocument print-tyustliusage…

【冒烟测试前置】如何把控提测质量?

你是否碰到过开发提测速度很快&#xff0c;导致项目排队&#xff0c;结果介入测试时&#xff0c;第一条用例都跑不通的情况&#xff1f; 你是否碰到过因为开发提测质量差&#xff0c;导致反复修改&#xff0c;反复提测&#xff0c;反复重复验证的情况&#xff1f; 你是否碰到…

sql数据类型,约束以及单表查询

嘎嘎学撒 数据类型约束条件DML 数据操作语句一、插入数据INSERT二、更新数据UPDATE三、删除数据DELETE四、MySQL单表查询五、关键词 数据类型 常见的数据类型 数值类型&#xff1a; 整数类型 TINYINT SMALLINT MEDIUMINT INT BIGINT 整型可以指定是有符号的和无符号的&#xf…

如何快速做跨业务测试?

当业务任务多且人力资源不充足的情况下&#xff0c;不同业务的同学可能需要去不同的业务进行临时支援&#xff0c;可能在时间方面有长有短&#xff0c;但是如何迈出第一步是很多人需要关心的一件事。 本文以实际跨业务测试经验&#xff08;订单业务测试人员如何测试售后业务&a…

【操作】国标GB28181视频监控EasyGBS平台更新设备信息时间间隔

国标GB28181协议视频平台EasyGBS是基于GB28181协议的视频监控云服务平台&#xff0c;可支持多路设备同时接入&#xff0c;并对多平台、多终端分发出RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。平台可提供视频监控直播、云端录像、云存储、检索回放、智能告警、语音对讲、平台…

[Python进阶] Pyinstaller打包程序时为程序添加图标

5.5 Pyinstaller打包程序时为程序添加图标 5.5.1 程序图标的好处 增强可识别性&#xff1a;图标是一种视觉语言&#xff0c;能够提高应用程序的可识别性&#xff0c;使其在众多应用程序中更容易被用户找到和识别。 帮助用户理解应用程序功能&#xff1a;图标可以快速传达应用…

硬件基本功--电阻/电容/电感/二极管

一、电阻 电阻的主要参数&#xff1a;阻值、精度、封装、功率、耐压 电阻在电路中的作用&#xff1a;分压、限流、采样、偏置等等 阻值&#xff1a;103 10*1000 10KΩ 电阻流过电流&#xff0c;就会有压降&#xff0c;从而产生功率损耗 电阻封装、功率、耐压的关系&#xff1…

青云1000----华为昇腾310 注意事项

青云1000帮助文档 只是一部分&#xff0c;后续遇到的问题会补充 注意事项&#xff01;&#xff01;&#xff01;&#xff01; type-c只用于数据传输不能供电DC供电和锂电池不能同时供电&#xff0c;会烧掉风扇正负级不要插反 账户密码 HwHiAiUser 密码Mind123 TypeC USB …

接口测试——接口协议抓包分析与mock_L2

目录&#xff1a; 抓包工具charles抓包工具fiddler抓包工具证书配置app抓包实战练习接口测试实战练习 1.抓包工具charles 工具介绍 支持 SSL 代理支持流量控制支持重发网络请求&#xff0c;方便后端调试支持修改网络请求参数支持网络请求的截获并动态修改可以自动将 json 或…

七、栈与队列(stack and queue)

文章目录 一、栈与队列基础二、例题&#xff08;一&#xff09;栈1.[232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/description/)&#xff08;1&#xff09;思路&#xff08;2&#xff09;代码&#xff08;3&#xff09;复杂度分析 2.[225. …

海大校园学习《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著

海大校园学习《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著

pytorch固定随机数中种子

1、添加到yolov7的utils/general.py文件最下面 import pkg_resources as pkg def check_version(current0.0.0, minimum0.0.0, nameversion , pinnedFalse, hardFalse, verboseFalse):# Check version vs. required versioncurrent, minimum (pkg.parse_version(x) for x in …