c++设计模式之工厂模式和单列模式和代理模式,观察者模式
本文转载自:https://www.cnblogs.com/cxq0017/p/6544517.html
1:简单工厂模式
简单工厂模式是属于创建型模式,又叫做静态工厂方法(static Factory Method)模式,简单工厂模式是由一个工厂对象决定创建出来哪一种产品类的实例.
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一类产品类(这些产品类继承自一个父类或接口)的实例。打个比方
假设有一个工厂,他能生产出A、B两种产品。当客户需要产品的时候一定要告诉共产是哪种产品,是A还是B。当新增加一种新产品的时候,那么就要去修改工厂的类。
1 // Factory.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 7 using namespace std; 8 9 class Product 10 { 11 public: 12 virtual void show() = 0; 13 }; 14 15 class Product_A : public Product 16 { 17 public: 18 void show() 19 { 20 cout << "Product_A" << endl; 21 } 22 }; 23 24 class Product_B : public Product 25 { 26 public: 27 void show() 28 { 29 cout << "Product_B" << endl; 30 } 31 }; 32 33 class Factory 34 { 35 public: 36 Product* Create(int i) 37 { 38 switch (i) 39 { 40 case 1: 41 return new Product_A; 42 break; 43 case 2: 44 return new Product_B; 45 break; 46 default: 47 break; 48 } 49 } 50 }; 51 52 int main() 53 { 54 Factory *factory = new Factory(); 55 factory->Create(1)->show(); 56 factory->Create(2)->show(); 57 system("pause"); 58 return 0; 59 }
二:工厂方法模式:
上面的简单工厂模式的缺点是当新增产品的时候就要去修改工厂的类,这就违反了开放封闭原则,(类、模块、函数)可以扩展,但是不可以修改,于是,就出现了工厂方法模式。所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。打个比方
现在有A、B两种产品,那么久开两个工厂。工厂A负责生产A产品,工厂B负责生产B种产品。这时候客户不需要告诉共产生产哪种产品了,只需要告诉共产生产就可以了。
1 #include "stdafx.h" 2 #include<iostream> 3 4 using namespace std; 5 6 class Product 7 { 8 public: 9 virtual void show() = 0; 10 }; 11 12 class Product_A : public Product 13 { 14 public: 15 void show() 16 { 17 cout << "Product_A" << endl; 18 } 19 }; 20 21 class Product_B : public Product 22 { 23 public: 24 void show() 25 { 26 cout << "Product_B" << endl; 27 } 28 }; 29 30 class Factory 31 { 32 public: 33 virtual Product* create() = 0; 34 }; 35 36 class Factory_A : public Factory 37 { 38 public: 39 Product* create() 40 { 41 return new Product_A; 42 } 43 }; 44 45 class Factory_B : public Factory 46 { 47 public: 48 Product* create() 49 { 50 return new Product_B; 51 } 52 }; 53 54 int main() 55 { 56 Factory_A* productA = new Factory_A(); 57 Factory_B* productB = new Factory_B(); 58 59 productA->create()->show(); 60 productB->create()->show(); 61 system("pause"); 62 return 0; 63 }
抽象工厂模式
为什么要有抽象工厂模式,假如我们A产品中有A1和A2两种型号的厂品,B产品中有B1和B2两种型号的厂品,那怎么办,上面两种工厂模式就不能解决了。这个时候抽象工厂模式就登场了。还是开设两家工厂,工厂A负责生产A1 、A2型号产品,B工厂负责生产B1、B2型号的产品。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 适用性:一个系统要独立于它的产品的创建、组合和表示时。一个系统要由多个产品系列中的一个来配置时。当你要强调一系列相关的产品对象的设计以便进行联合使用时。当你提供一个产品类库,而只想显示它们的接口而不是实现时。
1 #include <iostream> 2 using namespace std; 3 4 //定义抽象类 5 class product1 6 { 7 public: 8 virtual void show() = 0; 9 }; 10 11 //定义具体类 12 class product_A1 :public product1 13 { 14 public: 15 void show(){ cout << "product A1" << endl; } 16 }; 17 18 class product_B1 :public product1 19 { 20 public: 21 void show(){ cout << "product B1" << endl; } 22 }; 23 24 //定义抽象类 25 class product2 26 { 27 public: 28 virtual void show() = 0; 29 }; 30 31 //定义具体类 32 class product_A2 :public product2 33 { 34 public: 35 void show(){ cout << "product A2" << endl; } 36 }; 37 38 class product_B2 :public product2 39 { 40 public: 41 void show(){ cout << "product B2" << endl; } 42 }; 43 44 45 class Factory 46 { 47 public: 48 virtual product1 *creat1() = 0; 49 virtual product2 *creat2() = 0; 50 }; 51 52 class FactoryA 53 { 54 public: 55 product1 *creat1(){ return new product_A1(); } 56 product2 *creat2(){ return new product_A2(); } 57 }; 58 59 class FactoryB 60 { 61 public: 62 product1 *creat1(){ return new product_B1(); } 63 product2 *creat2(){ return new product_B2(); } 64 }; 65 66 int main() 67 { 68 FactoryA *factoryA = new FactoryA(); 69 factoryA->creat1()->show(); 70 factoryA->creat2()->show(); 71 72 FactoryB *factoryB = new FactoryB(); 73 factoryB->creat1()->show(); 74 factoryB->creat2()->show(); 75 76 return 0; 77 }
单例模式
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能阻止你实例化多个对象。一个最好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
也就是说,很多时候我们需要全局的对象,如一个工程中,数据库访问对象只有一个,这时,可以考虑使用单例模式。单例模式比全局对象好还包括:单例类可以继承,如下例中的C++代码。
单例模式的关键点在于:构造函数私有,静态的GetInstance。
另外,在C++中必须注意内存的释放。C++、Java、C#中还要注意多线程时的同步问题,另外在多线程可以以合适的方式保证共享变量仅初始化一次
以下列出懒汉式的单例模式
C++实现:
class Singleton { public: static Singleton * GetInstance() { if(NULL == m_pInstance) m_pInstance = new Singleton(); return m_pInstance; } static void Release() //必须,否则会导致内存泄露 { if(NULL != m_pInstance) { delete m_pInstance; m_pInstance = NULL; } } protected: Singleton() { cout<<"C++ Singleton"<<endl; }; static Singleton * m_pInstance; }; Singleton* Singleton::m_pInstance = NULL; class SingleDraw:public Singleton { public: static SingleDraw* GetInstance() { if(NULL == m_pInstance) m_pInstance = new SingleDraw(); return (SingleDraw*)m_pInstance; } protected: SingleDraw() { cout<<"C++ SingleDraw"<<endl; } }; int main() { SingleDraw* s1 = SingleDraw::GetInstance(); SingleDraw* s2 = SingleDraw::GetInstance(); s2->Release(); return 0; }
一:代理模式简介
专业版描述:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
戏剧性描述:房产市场不稳定,房价涨了还是涨。隔壁老王要买房,忍痛找到房产中介,中介把房介绍给老王,老王买到中意房。
这个剧情中老王是主角,演绎了一个买房的故事。房产中介是老王的代理,房子是老王的需求对象,由于中介有房产资源,老王又无法直接找到房源,只能找到中介去买房。
二:实践
老王的故事在程序中得以实现。
1.协议定义:买房协议(BuyRoomDelegate)。只有拥有买房协议才能成为房产中介。 2.代理者:房产中介(RoomDelegate),他继承买房协议。
3.需要代理者:买房人(BuyRoomPerson),买房需要找代理。
编码如下:
买房协议(BuyRoomDelegate):
#pragma once #include <functional> //函数定义:完成代理任务后给请求者反馈 typedef std::function<void(bool succeed, std::string msg)> RoomHandleCallback; #pragma region BuyRoomDelegate //买房协议 class BuyRoomDelegate { public: BuyRoomDelegate() {} ~BuyRoomDelegate() {} public: //买房 virtual bool TryBuy(std::string condition, RoomHandleCallback callback) = 0; }; #pragma endregion
房产中介(RoomDelegate):
#pragma region RoomDelegate //房产中介 class RoomDelegate:public BuyRoomDelegate//, public RoomSellerDelegate { public: RoomDelegate() {} ~RoomDelegate() {} public: //实现父类接口 //买房 bool TryBuy(std::string condition, RoomHandleCallback callback); ////卖房 // void Selling(); private: }; #pragma endregion //RoomDelegate.cpp #include "stdafx.h" #include "RoomDelegate.h" bool RoomDelegate::TryBuy(std::string condition, RoomHandleCallback callback) { cout << "中介找房:" << condition << endl; int a = rand() % 2; bool succeed = a == 0;//如果a==0,买房成功 string msg = ""; if (succeed)//成功 { msg = "中介:恭喜啊"; cout << "中介:终于卖出了一套房" << endl; } else { msg = "中介:对不住呀,这条件不好找呀!"; cout << "中介:这条件太难找了。。。" << endl; } if (callback != nullptr) { callback(succeed, msg); } return succeed; }
买房人(BuyRoomPerson):
#pragma once class BuyRoomDelegate; //买房人 class BuyRoomPerson { public: BuyRoomPerson(); ~BuyRoomPerson(); //买房 bool Buy(std::string condition); public: //设置买房代理 void setBuyRoomDelegate(BuyRoomDelegate* buyRoomDelegate) { m_buyRoomDelegate = buyRoomDelegate; } private: //买房代理 BuyRoomDelegate* m_buyRoomDelegate; }; //BuyRoomPerson.cpp #include "stdafx.h" BuyRoomPerson::BuyRoomPerson() { m_buyRoomDelegate = nullptr; } BuyRoomPerson::~BuyRoomPerson() { } bool BuyRoomPerson::Buy(std::string condition) { if (m_buyRoomDelegate != nullptr) { //string condition = "90万,90平,石家庄裕华区"; //Lambda 表达式 bool succeed = m_buyRoomDelegate->TryBuy(condition, [condition, this/*向表达式传参,临时参数、成员参数*/](bool succeed, std::string msg/*参数*/)->void/*返回值类型*/{ if (succeed) { cout<< "买房成功" << condition <<endl; } else { cout << "没有谈妥,买房失败"<<condition << endl; } }); return succeed; } return false; }
测试代码:
int main() { //房产中介 RoomDelegate* roomDel = new RoomDelegate(); //买房人 BuyRoomPerson* buyPer = new BuyRoomPerson(); //买房人找个中介帮忙买房 buyPer->setBuyRoomDelegate(roomDel); for (size_t i = 0; i < 10; i++) { //买房人向中介查询能否买到指定条件的房子 bool succeed = buyPer->Buy("90万,90平,石家庄裕华区"); cout << "=============================次数:"<<i<<endl; if (succeed)//如果买房成功了,就不买了 break; } while (true) { char a; cin >> a; } }
输出结果:
中介找房:90万,90平,石家庄裕华区 中介:这条件太难找了。。。 没有谈妥,买房失败90万,90平,石家庄裕华区 =============================次数:0 中介找房:90万,90平,石家庄裕华区 中介:这条件太难找了。。。 没有谈妥,买房失败90万,90平,石家庄裕华区 =============================次数:1 中介找房:90万,90平,石家庄裕华区 中介:终于卖出了一套房 买房成功90万,90平,石家庄裕华区 =============================次数:2
观察者模式角色如下:
抽象主题(Subject)角色:抽象主题角色提供维护一个观察者对象聚集的操作方法,对聚集的增加、删除等。
具体主题(ConcreteSubject)角色:将有关状态存入具体的观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色负责实现抽象主题中聚集的管理方法。
抽象观察者(Observer)角色:为具体观察者提供一个更新接口。
具体观察者(ConcreteObserver)角色:存储与主题相关的自洽状态,实现抽象观察者提供的更新接口。
uml图:
案例:在教室里老师还没有来,同学都在干着各的事情,小张正在打游戏,小李正在抄作业....., 现在同学们要求班长当卧底,监视老师,当老师来了通知大家一声。然后打游戏的马上停止,抄作业的也停止。
这里班长相当于是一个通知者, 小张、小李,以及其他同学显然是监听者,他们监听了班长那的消息,一旦老师来了马上采取相关的行动。
首先,先把通知真的行为抽象为一个接口(因为,子类可能监听的东西不同,可能学习委员监听班主任老师,班长监听数学老师等等,但是我们这里这个例子监听没有那么仔细。)
- class INotifier
- {
- public:
- virtual void addListenner(TecherListenner* listenner) = 0;
- virtual void removeListenner(TecherListenner* listenner) = 0;
- virtual void notify() = 0;
- };
然后班长作为一个具体的通知者:
- class TecherNotifier : public INotifier
- {
- public:
- virtual void addListenner(TecherListenner* listenner)
- {
- m_listenners.push_back(listenner);
- }
- virtual void removeListenner(TecherListenner* listenner)
- {
- //if contains();
- m_listenners.remove(listenner);
- delete listenner;
- }
- virtual void notify()
- {
- list <TecherListenner*> ::iterator it = m_listenners.begin();
- for (; it != m_listenners.end(); ++ it)
- {
- (*it)->onTecherComming();//通知大家,老师来了
- }
- }
- private:
- list<TecherListenner*> m_listenners;
- };
定义一个监听者的接口,想要监听老师来了这个消息的同学必须要实现这个接口:
- class TecherListenner
- {
- public:
- virtual void onTecherComming() = 0;
- };
- class XiaoZhang : public TecherListenner
- {
- public:
- virtual void onTecherComming()
- {
- stopCopyWork();
- }
- void stopCopyWork()
- {
- cout<<"老师来了,停止抄作业!"<<endl;
- }
- };
- class XiaoLi : public TecherListenner
- {
- public:
- virtual void onTecherComming()
- {
- stopPlayGame();
- }
- void stopPlayGame()
- {
- cout<<"老师来了,停止玩游戏机!"<<endl;
- }
- };
这样当老师来了,小张和小李就可以停止玩游戏和抄作业,避免被老师发现。
客户端代码:
- TecherNotifier monitor;
- XiaoZhang xz;
- XiaoLi xl;
- monitor.addListenner(&xz);
- monitor.addListenner(&xl);
- xz.copyHomeWork();
- xl.playGame();
- monitor.notify();