C++ 常用设计模式(学习笔记)

设计模式

1、工厂模式

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。工厂模式作为一种创建模式,一般在创建复杂对象时,考虑使用;在创建简单对象时,建议直接new完成一个实例对象的创建。

1.1、简单工厂模式

主要特点是需要在工厂类中做判断,从而创造相应的产品,当增加新产品时,需要修改工厂类。使用简单工厂模式,我们只需要知道具体的产品型号就可以创建一个产品。

缺点:工厂类集中了所有产品类的创建逻辑,如果产品量较大,会使得工厂类变的非常臃肿。

1 1 /* 2 2 关键代码:创建过程在工厂类中完成。 3 3 */ 4 45 5 #include <iostream> 6 67 7 using namespace std; 8 89 9 //定义产品类型信息 1010 typedef enum 1111 { 1212 Tank_Type_56, 1313 Tank_Type_96, 1414 Tank_Type_Num 1515 }Tank_Type; 16161717 //抽象产品类 1818 class Tank 1919 { 2020 public: 2121 virtual const string& type() = 0; 2222 }; 23232424 //具体的产品类 2525 class Tank56 : public Tank 2626 { 2727 public: 2828 Tank56():Tank(),m_strType("Tank56") 2929 { 3030 } 31313232 const string& type() override 3333 { 3434 cout << m_strType.data() << endl; 3535 return m_strType; 3636 } 3737 private: 3838 string m_strType; 3939 }; 40404141 //具体的产品类 4242 class Tank96 : public Tank 4343 { 4444 public: 4545 Tank96():Tank(),m_strType("Tank96") 4646 { 4747 } 4848 const string& type() override 4949 { 5050 cout << m_strType.data() << endl; 5151 return m_strType; 5252 } 53535454 private: 5555 string m_strType; 5656 }; 57575858 //工厂类 5959 class TankFactory 6060 { 6161 public: 6262 //根据产品信息创建具体的产品类实例,返回一个抽象产品类 6363 Tank* createTank(Tank_Type type) 6464 { 6565 switch(type) 6666 { 6767 case Tank_Type_56: 6868 return new Tank56(); 6969 case Tank_Type_96: 7070 return new Tank96(); 7171 default: 7272 return nullptr; 7373 } 7474 } 7575 }; 767677777878 int main() 7979 { 8080 TankFactory* factory = new TankFactory(); 8181 Tank* tank56 = factory->createTank(Tank_Type_56); 8282 tank56->type(); 8383 Tank* tank96 = factory->createTank(Tank_Type_96); 8484 tank96->type(); 85858686 delete tank96; 8787 tank96 = nullptr; 8888 delete tank56; 8989 tank56 = nullptr; 9090 delete factory; 9191 factory = nullptr; 92929393 return 0; 9494 }

1.2、工厂方法模式

定义一个创建对象的接口,其子类去具体现实这个接口以完成具体的创建工作。如果需要增加新的产品类,只需要扩展一个相应的工厂类即可。

缺点:产品类数据较多时,需要实现大量的工厂类,这无疑增加了代码量。

1 1 /* 2 2 关键代码:创建过程在其子类执行。 3 3 */ 4 45 5 #include <iostream> 6 67 7 using namespace std; 8 89 9 //产品抽象类 10 10 class Tank 11 11 { 12 12 public: 13 13 virtual const string& type() = 0; 14 14 }; 15 1516 16 //具体的产品类 17 17 class Tank56 : public Tank 18 18 { 19 19 public: 20 20 Tank56():Tank(),m_strType("Tank56") 21 21 { 22 22 } 23 2324 24 const string& type() override 25 25 { 26 26 cout << m_strType.data() << endl; 27 27 return m_strType; 28 28 } 29 29 private: 30 30 string m_strType; 31 31 }; 32 3233 33 //具体的产品类 34 34 class Tank96 : public Tank 35 35 { 36 36 public: 37 37 Tank96():Tank(),m_strType("Tank96") 38 38 { 39 39 } 40 40 const string& type() override 41 41 { 42 42 cout << m_strType.data() << endl; 43 43 return m_strType; 44 44 } 45 4546 46 private: 47 47 string m_strType; 48 48 }; 49 4950 50 //抽象工厂类,提供一个创建接口 51 51 class TankFactory 52 52 { 53 53 public: 54 54 //提供创建产品实例的接口,返回抽象产品类 55 55 virtual Tank* createTank() = 0; 56 56 }; 57 5758 58 //具体的创建工厂类,使用抽象工厂类提供的接口,去创建具体的产品实例 59 59 class Tank56Factory : public TankFactory 60 60 { 61 61 public: 62 62 Tank* createTank() override 63 63 { 64 64 return new Tank56(); 65 65 } 66 66 }; 67 6768 68 //具体的创建工厂类,使用抽象工厂类提供的接口,去创建具体的产品实例 69 69 class Tank96Factory : public TankFactory 70 70 { 71 71 public: 72 72 Tank* createTank() override 73 73 { 74 74 return new Tank96(); 75 75 } 76 76 }; 77 7778 7879 79 int main() 80 80 { 81 81 TankFactory* factory56 = new Tank56Factory(); 82 82 Tank* tank56 = factory56->createTank(); 83 83 tank56->type(); 84 84 85 85 TankFactory* factory96 = new Tank96Factory(); 86 86 Tank* tank96 = factory96->createTank(); 87 87 tank96->type(); 88 8889 89 delete tank96; 90 90 tank96 = nullptr; 91 91 delete factory96; 92 92 factory96 = nullptr; 93 9394 94 delete tank56; 95 95 tank56 = nullptr; 96 96 delete factory56; 97 97 factory56 = nullptr; 98 9899 99 return 0; 100100 }

1.3、抽象工厂模式

抽象工厂模式提供创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

当存在多个产品系列,而客户端只使用一个系列的产品时,可以考虑使用抽象工厂模式。

缺点:当增加一个新系列的产品时,不仅需要现实具体的产品类,还需要增加一个新的创建接口,扩展相对困难。

1 1 /* 2 2 * 关键代码:在一个工厂里聚合多个同类产品。 3 3 * 以下代码以白色衣服和黑色衣服为例,白色衣服为一个产品系列,黑色衣服为一个产品系列。白色上衣搭配白色裤子, 黑色上衣搭配黑色裤字。每个系列的衣服由一个对应的工厂创建,这样一个工厂创建的衣服能保证衣服为同一个系列。 4 4 */ 5 56 6 //抽象上衣类 7 7 class Coat 8 8 { 9 9 public: 10 10 virtual const string& color() = 0; 11 11 }; 12 1213 13 //黑色上衣类 14 14 class BlackCoat : public Coat 15 15 { 16 16 public: 17 17 BlackCoat():Coat(),m_strColor("Black Coat") 18 18 { 19 19 } 20 2021 21 const string& color() override 22 22 { 23 23 cout << m_strColor.data() << endl; 24 24 return m_strColor; 25 25 } 26 26 private: 27 27 string m_strColor; 28 28 }; 29 2930 30 //白色上衣类 31 31 class WhiteCoat : public Coat 32 32 { 33 33 public: 34 34 WhiteCoat():Coat(),m_strColor("White Coat") 35 35 { 36 36 } 37 37 const string& color() override 38 38 { 39 39 cout << m_strColor.data() << endl; 40 40 return m_strColor; 41 41 } 42 4243 43 private: 44 44 string m_strColor; 45 45 }; 46 4647 47 //抽象裤子类 48 48 class Pants 49 49 { 50 50 public: 51 51 virtual const string& color() = 0; 52 52 }; 53 5354 54 //黑色裤子类 55 55 class BlackPants : public Pants 56 56 { 57 57 public: 58 58 BlackPants():Pants(),m_strColor("Black Pants") 59 59 { 60 60 } 61 61 const string& color() override 62 62 { 63 63 cout << m_strColor.data() << endl; 64 64 return m_strColor; 65 65 } 66 6667 67 private: 68 68 string m_strColor; 69 69 }; 70 7071 71 //白色裤子类 72 72 class WhitePants : public Pants 73 73 { 74 74 public: 75 75 WhitePants():Pants(),m_strColor("White Pants") 76 76 { 77 77 } 78 78 const string& color() override 79 79 { 80 80 cout << m_strColor.data() << endl; 81 81 return m_strColor; 82 82 } 83 8384 84 private: 85 85 string m_strColor; 86 86 }; 87 8788 88 //抽象工厂类,提供衣服创建接口 89 89 class Factory 90 90 { 91 91 public: 92 92 //上衣创建接口,返回抽象上衣类 93 93 virtual Coat* createCoat() = 0; 94 94 //裤子创建接口,返回抽象裤子类 95 95 virtual Pants* createPants() = 0; 96 96 }; 97 9798 98 //创建白色衣服的工厂类,具体实现创建白色上衣和白色裤子的接口 99 99 class WhiteFactory : public Factory 100100 { 101101 public: 102102 Coat* createCoat() override 103103 { 104104 return new WhiteCoat(); 105105 } 106106107107 Pants* createPants() override 108108 { 109109 return new WhitePants(); 110110 } 111111 }; 112112113113 //创建黑色衣服的工厂类,具体实现创建黑色上衣和白色裤子的接口 114114 class BlackFactory : public Factory 115115 { 116116 Coat* createCoat() override 117117 { 118118 return new BlackCoat(); 119119 } 120120121121 Pants* createPants() override 122122 { 123123 return new BlackPants(); 124124 } 125125 };

2、策略模式

策略模式是指定义一系列的算法,把它们单独封装起来,并且使它们可以互相替换,使得算法可以独立于使用它的客户端而变化,也是说这些算法所完成的功能类型是一样的,对外接口也是一样的,只是不同的策略为引起环境角色环境角色表现出不同的行为。

相比于使用大量的if...else,使用策略模式可以降低复杂度,使得代码更容易维护。

缺点:可能需要定义大量的策略类,并且这些策略类都要提供给客户端。

[ 环境角色]  持有一个策略类的引用,最终给客户端调用。

2.1、传统的策略模式实现

1 1 /* 2 2 * 关键代码:实现同一个接口。 3 3 * 以下代码实例中,以游戏角色不同的攻击方式为不同的策略,游戏角色即为执行不同策略的环境角色。 4 4 */ 5 56 6 #include <iostream> 7 78 8 using namespace std; 9 910 10 //抽象策略类,提供一个接口 11 11 class Hurt 12 12 { 13 13 public: 14 14 virtual void blood() = 0; 15 15 }; 16 1617 17 //具体的策略实现类,具体实现接口, Adc持续普通攻击 18 18 class AdcHurt : public Hurt 19 19 { 20 20 public: 21 21 void blood() override 22 22 { 23 23 cout << "Adc hurt, Blood loss" << endl; 24 24 } 25 25 }; 26 2627 27 //具体的策略实现类,具体实现接口, Apc技能攻击 28 28 class ApcHurt : public Hurt 29 29 { 30 30 public: 31 31 void blood() override 32 32 { 33 33 cout << "Apc Hurt, Blood loss" << endl; 34 34 } 35 35 }; 36 3637 37 //环境角色类, 游戏角色战士,传入一个策略类指针参数。 38 38 class Soldier 39 39 { 40 40 public: 41 41 Soldier(Hurt* hurt):m_pHurt(hurt) 42 42 { 43 43 } 44 44 //在不同的策略下,该游戏角色表现出不同的攻击 45 45 void attack() 46 46 { 47 47 m_pHurt->blood(); 48 48 } 49 49 private: 50 50 Hurt* m_pHurt; 51 51 }; 52 5253 53 //定义策略标签 54 54 typedef enum 55 55 { 56 56 Hurt_Type_Adc, 57 57 Hurt_Type_Apc, 58 58 Hurt_Type_Num 59 59 }HurtType; 60 6061 61 //环境角色类, 游戏角色法师,传入一个策略标签参数。 62 62 class Mage 63 63 { 64 64 public: 65 65 Mage(HurtType type) 66 66 { 67 67 switch(type) 68 68 { 69 69 case Hurt_Type_Adc: 70 70 m_pHurt = new AdcHurt(); 71 71 break; 72 72 case Hurt_Type_Apc: 73 73 m_pHurt = new ApcHurt(); 74 74 break; 75 75 default: 76 76 break; 77 77 } 78 78 } 79 79 ~Mage() 80 80 { 81 81 delete m_pHurt; 82 82 m_pHurt = nullptr; 83 83 cout << "~Mage()" << endl; 84 84 } 85 8586 86 void attack() 87 87 { 88 88 m_pHurt->blood(); 89 89 } 90 90 private: 91 91 Hurt* m_pHurt; 92 92 }; 93 9394 94 //环境角色类, 游戏角色弓箭手,实现模板传递策略。 95 95 template<typename T> 96 96 class Archer 97 97 { 98 98 public: 99 99 void attack() 100100 { 101101 m_hurt.blood(); 102102 } 103103 private: 104104 T m_hurt; 105105 }; 106106107107 int main() 108108 { 109109 Archer<ApcHurt>* arc = new Archer<ApcHurt>; 110110 arc->attack(); 111111112112 delete arc; 113113 arc = nullptr; 114114 115115 return 0; 116116 }

2.2、使用函数指针实现策略模式

1 1 #include <iostream> 2 2 #include <functional> 3 34 4 void adcHurt() 5 5 { 6 6 std::cout << "Adc Hurt" << std::endl; 7 7 } 8 89 9 void apcHurt() 1010 { 1111 std::cout << "Apc Hurt" << std::endl; 1212 } 13131414 //环境角色类, 使用传统的函数指针 1515 class Soldier 1616 { 1717 public: 1818 typedef void (*Function)(); 1919 Soldier(Function fun): m_fun(fun) 2020 { 2121 } 2222 void attack() 2323 { 2424 m_fun(); 2525 } 2626 private: 2727 Function m_fun; 2828 }; 29293030 //环境角色类, 使用std::function<> 3131 class Mage 3232 { 3333 public: 3434 typedef std::function<void()> Function; 35353636 Mage(Function fun): m_fun(fun) 3737 { 3838 } 3939 void attack() 4040 { 4141 m_fun(); 4242 } 4343 private: 4444 Function m_fun; 4545 }; 46464747 int main() 4848 { 4949 Soldier* soldier = new Soldier(apcHurt); 5050 soldier->attack(); 5151 delete soldier; 5252 soldier = nullptr; 5353 return 0; 5454 }

3、适配器模式

适配器模式可以将一个类的接口转换成客户端希望的另一个接口,使得原来由于接口不兼容而不能在一起工作的那些类可以在一起工作。通俗的讲就是当我们已经有了一些类,而这些类不能满足新的需求,此时就可以考虑是否能将现有的类适配成可以满足新需求的类。适配器类需要继承或依赖已有的类,实现想要的目标接口。

缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

3.1、使用复合实现适配器模式

1 1 /* 2 2 * 关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。 3 3 * 以下示例中,假设我们之前有了一个双端队列,新的需求要求使用栈和队列来完成。 4 4 双端队列可以在头尾删减或增加元素。而栈是一种先进后出的数据结构,添加数据时添加到栈的顶部,删除数据时先删 除栈顶部的数据。因此我们完全可以将一个现有的双端队列适配成一个栈。 5 5 */ 6 67 7 //双端队列, 被适配类 8 8 class Deque 9 9 { 1010 public: 1111 void push_back(int x) 1212 { 1313 cout << "Deque push_back:" << x << endl; 1414 } 1515 void push_front(int x) 1616 { 1717 cout << "Deque push_front:" << x << endl; 1818 } 1919 void pop_back() 2020 { 2121 cout << "Deque pop_back" << endl; 2222 } 2323 void pop_front() 2424 { 2525 cout << "Deque pop_front" << endl; 2626 } 2727 }; 28282929 //顺序类,抽象目标类 3030 class Sequence 3131 { 3232 public: 3333 virtual void push(int x) = 0; 3434 virtual void pop() = 0; 3535 }; 36363737 //栈,后进先出, 适配类 3838 class Stack:public Sequence 3939 { 4040 public: 4141 //将元素添加到堆栈的顶部。 4242 void push(int x) override 4343 { 4444 m_deque.push_front(x); 4545 } 4646 //从堆栈中删除顶部元素 4747 void pop() override 4848 { 4949 m_deque.pop_front(); 5050 } 5151 private: 5252 Deque m_deque; 5353 }; 54545555 //队列,先进先出,适配类 5656 class Queue:public Sequence 5757 { 5858 public: 5959 //将元素添加到队列尾部 6060 void push(int x) override 6161 { 6262 m_deque.push_back(x); 6363 } 6464 //从队列中删除顶部元素 6565 void pop() override 6666 { 6767 m_deque.pop_front(); 6868 } 6969 private: 7070 Deque m_deque; 7171 };

3.2、使用继承实现适配器模式

1 1 //双端队列,被适配类 2 2 class Deque 3 3 { 4 4 public: 5 5 void push_back(int x) 6 6 { 7 7 cout << "Deque push_back:" << x << endl; 8 8 } 9 9 void push_front(int x) 1010 { 1111 cout << "Deque push_front:" << x << endl; 1212 } 1313 void pop_back() 1414 { 1515 cout << "Deque pop_back" << endl; 1616 } 1717 void pop_front() 1818 { 1919 cout << "Deque pop_front" << endl; 2020 } 2121 }; 22222323 //顺序类,抽象目标类 2424 class Sequence 2525 { 2626 public: 2727 virtual void push(int x) = 0; 2828 virtual void pop() = 0; 2929 }; 30303131 //栈,后进先出, 适配类 3232 class Stack:public Sequence, private Deque 3333 { 3434 public: 3535 void push(int x) 3636 { 3737 push_front(x); 3838 } 3939 void pop() 4040 { 4141 pop_front(); 4242 } 4343 }; 44444545 //队列,先进先出,适配类 4646 class Queue:public Sequence, private Deque 4747 { 4848 public: 4949 void push(int x) 5050 { 5151 push_back(x); 5252 } 5353 void pop() 5454 { 5555 pop_front(); 5656 } 5757 };

4、单例模式

单例模式顾名思义,保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意一下几点:

  • 单例类只能由一个实例化对象。

  • 单例类必须自己提供一个实例化对象。

  • 单例类必须提供一个可以访问唯一实例化对象的接口。

单例模式分为懒汉和饿汉两种实现方式。

4.1、懒汉单例模式

懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化一个对象。在访问量较小,甚至可能不会去访问的情况下,采用懒汉实现,这是以时间换空间。

4.1.1、非线程安全的懒汉单例模式

1 1 /* 2 2 * 关键代码:构造函数是私有的,不能通过赋值运算,拷贝构造等方式实例化对象。 3 3 */ 4 45 5 //懒汉式一般实现:非线程安全,getInstance返回的实例指针需要delete 6 6 class Singleton 7 7 { 8 8 public: 9 9 static Singleton* getInstance(); 1010 ~Singleton(){} 11111212 private: 1313 Singleton(){} //构造函数私有 1414 Singleton(const Singleton& obj) = delete; //明确拒绝 1515 Singleton& operator=(const Singleton& obj) = delete; //明确拒绝 1616 1717 static Singleton* m_pSingleton; 1818 }; 19192020 Singleton* Singleton::m_pSingleton = NULL; 21212222 Singleton* Singleton::getInstance() 2323 { 2424 if(m_pSingleton == NULL) 2525 { 2626 m_pSingleton = new Singleton; 2727 } 2828 return m_pSingleton; 2929 }

4.1.2、线程安全的懒汉单例模式

1 1 std::mutex mt; 2 2 3 3 class Singleton 4 4 { 5 5 public: 6 6 static Singleton* getInstance(); 7 7 private: 8 8 Singleton(){} //构造函数私有 9 9 Singleton(const Singleton&) = delete; //明确拒绝 1010 Singleton& operator=(const Singleton&) = delete; //明确拒绝 1111 1212 static Singleton* m_pSingleton; 1313 1414 }; 1515 Singleton* Singleton::m_pSingleton = NULL; 1616 1717 Singleton* Singleton::getInstance() 1818 { 1919 if(m_pSingleton == NULL) 2020 { 2121 mt.lock(); 2222 if(m_pSingleton == NULL) 2323 { 2424 m_pSingleton = new Singleton(); 2525 } 2626 mt.unlock(); 2727 } 2828 return m_pSingleton; 2929 }

4.1.3、返回一个reference指向local static对象

这种单例模式实现方式多线程可能存在不确定性:任何一种non-const static对象,不论它是local或non-local,在多线程环境下“等待某事发生”都会有麻烦。解决的方法:在程序的单线程启动阶段手工调用所有reference-returning函数。这种实现方式的好处是不需要去delete它。

1 1 class Singleton 2 2 { 3 3 public: 4 4 static Singleton& getInstance(); 5 5 private: 6 6 Singleton(){} 7 7 Singleton(const Singleton&) = delete; //明确拒绝 8 8 Singleton& operator=(const Singleton&) = delete; //明确拒绝 9 9 }; 101011111212 Singleton& Singleton::getInstance() 1313 { 1414 static Singleton singleton; 1515 return singleton; 1616 }

4.2、饿汉单例模式

饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

1 1 //饿汉式:线程安全,注意一定要在合适的地方去delete它 2 2 class Singleton 3 3 { 4 4 public: 5 5 static Singleton* getInstance(); 6 6 private: 7 7 Singleton(){} //构造函数私有 8 8 Singleton(const Singleton&) = delete; //明确拒绝 9 9 Singleton& operator=(const Singleton&) = delete; //明确拒绝 10101111 static Singleton* m_pSingleton; 1212 }; 13131414 Singleton* Singleton::m_pSingleton = new Singleton(); 15151616 Singleton* Singleton::getInstance() 1717 { 1818 return m_pSingleton; 1919 }

5、原型模式

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。通俗的讲就是当需要创建一个新的实例化对象时,我们刚好有一个实例化对象,但是已经存在的实例化对象又不能直接使用。这种情况下拷贝一个现有的实例化对象来用,可能会更方便。

以下情形可以考虑使用原型模式:

  • 当new一个对象,非常繁琐复杂时,可以使用原型模式来进行复制一个对象。比如创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程。

  • 当需要new一个新的对象,这个对象和现有的对象区别不大,我们就可以直接复制一个已有的对象,然后稍加修改。

  • 当需要一个对象副本时,比如需要提供对象的数据,同时又需要避免外部对数据对象进行修改,那就拷贝一个对象副本供外部使用。

    1 /* 2 * 关键代码:拷贝,return new className(this); 3 / 4 #include <iostream> 5 ​ 6 using namespace std; 7 ​ 8 //提供一个抽象克隆基类。 9 class Clone 10 { 11 public: 12 virtual Clone clone() = 0; 13 virtual void show() = 0; 14 }; 15 ​ 16 //具体的实现类 17 class Sheep:public Clone 18 { 19 public: 20 Sheep(int id, string name):Clone(), 21 m_id(id),m_name(name) 22 { 23 cout << "Sheep() id address:" << &m_id << endl; 24 cout << "Sheep() name address:" << &m_name << endl; 25 } 26 ~Sheep() 27 { 28 } 29 //关键代码拷贝构造函数 30 Sheep(const Sheep& obj) 31 { 32 this->m_id = obj.m_id; 33 this->m_name = obj.m_name; 34 cout << "Sheep(const Sheep& obj) id address:" << &m_id << endl; 35 cout << "Sheep(const Sheep& obj) name address:" << &m_name << endl; 36 } 37 //关键代码克隆函数,返回return new Sheep(this) 38 Clone clone() 39 { 40 return new Sheep(this); 41 } 42 void show() 43 { 44 cout << "id :" << m_id << endl; 45 cout << "name:" << m_name.data() << endl; 46 } 47 private: 48 int m_id; 49 string m_name; 50 }; 51 ​ 52 int main() 53 { 54 Clone s1 = new Sheep(1, "abs"); 55 s1->show(); 56 Clone s2 = s1->clone(); 57 s2->show(); 58
    59 delete s1; 60 s1 = nullptr; 61 delete s2; 62 s2 = nullptr; 63 return 0; 64 }

6、模板模式

模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

当多个类有相同的方法,并且逻辑相同,只是细节上有差异时,可以考虑使用模板模式。具体的实现上可以将相同的核心算法设计为模板方法,具体的实现细节有子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

以生产电脑为例,电脑生产的过程都是一样的,只是一些装配的器件可能不同而已。

1 1 /* 2 2 * 关键代码:在抽象类实现通用接口,细节变化在子类实现。 3 3 */ 4 45 5 #include <iostream> 6 67 7 using namespace std; 8 89 9 class Computer 1010 { 1111 public: 1212 void product() 1313 { 1414 installCpu(); 1515 installRam(); 1616 installGraphicsCard(); 1717 } 18181919 protected: 2020 virtual void installCpu() = 0; 2121 virtual void installRam() = 0; 2222 virtual void installGraphicsCard() = 0; 23232424 }; 25252626 class ComputerA : public Computer 2727 { 2828 protected: 2929 void installCpu() override 3030 { 3131 cout << "ComputerA install Inter Core i5" << endl; 3232 } 33333434 void installRam() override 3535 { 3636 cout << "ComputerA install 2G Ram" << endl; 3737 } 38383939 void installGraphicsCard() override 4040 { 4141 cout << "ComputerA install Gtx940 GraphicsCard" << endl; 4242 } 4343 }; 44444545 class ComputerB : public Computer 4646 { 4747 protected: 4848 void installCpu() override 4949 { 5050 cout << "ComputerB install Inter Core i7" << endl; 5151 } 52525353 void installRam() override 5454 { 5555 cout << "ComputerB install 4G Ram" << endl; 5656 } 57575858 void installGraphicsCard() override 5959 { 6060 cout << "ComputerB install Gtx960 GraphicsCard" << endl; 6161 } 6262 }; 63636464 int main() 6565 { 6666 ComputerB* c1 = new ComputerB(); 6767 c1->product(); 68686969 delete c1; 7070 c1 = nullptr; 71717272 return 0; 7373 }

7、建造者模式

建造者模式:将复杂对象的构建和其表示分离,使得相同的构建过程可以产生不同的表示。

以下情形可以考虑使用建造者模式:

  • 对象的创建复杂,但是其各个部分的子对象创建算法一定。

  • 需求变化大,构造复杂对象的子对象经常变化,但将其组合在一起的算法相对稳定。

建造者模式的优点:

  • 将对象的创建和表示分离,客户端不需要了解具体的构建细节。

  • 增加新的产品对象时,只需要增加其具体的建造类即可,不需要修改原来的代码,扩展方便。

产品之间差异性大,内部变化较大、较复杂时不建议使用建造者模式。

1 1 /* 2 2 *关键代码:建造者类:创建和提供实例; Director类:管理建造出来的实例的依赖关系。 3 3 */ 4 45 5 #include <iostream> 6 6 #include <string> 7 78 8 using namespace std; 9 910 10 //具体的产品类 11 11 class Order 12 12 { 13 13 public: 14 14 void setFood(const string& food) 15 15 { 16 16 m_strFood = food; 17 17 } 18 1819 19 const string& food() 20 20 { 21 21 cout << m_strFood.data() << endl; 22 22 return m_strFood; 23 23 } 24 24 25 25 void setDrink(const string& drink) 26 26 { 27 27 m_strDrink = drink; 28 28 } 29 2930 30 const string& drink() 31 31 { 32 32 cout << m_strDrink << endl; 33 33 return m_strDrink; 34 34 } 35 3536 36 private: 37 37 string m_strFood; 38 38 string m_strDrink; 39 39 }; 40 4041 41 //抽象建造类,提供建造接口。 42 42 class OrderBuilder 43 43 { 44 44 public: 45 45 virtual ~OrderBuilder() 46 46 { 47 47 cout << "~OrderBuilder()" << endl; 48 48 } 49 49 virtual void setOrderFood() = 0; 50 50 virtual void setOrderDrink() = 0; 51 51 virtual Order* getOrder() = 0; 52 52 }; 53 5354 54 //具体的建造类 55 55 class VegetarianOrderBuilder : public OrderBuilder 56 56 { 57 57 public: 58 58 VegetarianOrderBuilder() 59 59 { 60 60 m_pOrder = new Order; 61 61 } 62 6263 63 ~VegetarianOrderBuilder() 64 64 { 65 65 cout << "~VegetarianOrderBuilder()" << endl; 66 66 delete m_pOrder; 67 67 m_pOrder = nullptr; 68 68 } 69 6970 70 void setOrderFood() override 71 71 { 72 72 m_pOrder->setFood("vegetable salad"); 73 73 } 74 7475 75 void setOrderDrink() override 76 76 { 77 77 m_pOrder->setDrink("water"); 78 78 } 79 7980 80 Order* getOrder() override 81 81 { 82 82 return m_pOrder; 83 83 } 84 8485 85 private: 86 86 Order* m_pOrder; 87 87 }; 88 8889 89 //具体的建造类 90 90 class MeatOrderBuilder : public OrderBuilder 91 91 { 92 92 public: 93 93 MeatOrderBuilder() 94 94 { 95 95 m_pOrder = new Order; 96 96 } 97 97 ~MeatOrderBuilder() 98 98 { 99 99 cout << "~MeatOrderBuilder()" << endl; 100100 delete m_pOrder; 101101 m_pOrder = nullptr; 102102 } 103103104104 void setOrderFood() override 105105 { 106106 m_pOrder->setFood("beef"); 107107 } 108108109109 void setOrderDrink() override 110110 { 111111 m_pOrder->setDrink("beer"); 112112 } 113113114114 Order* getOrder() override 115115 { 116116 return m_pOrder; 117117 } 118118119119 private: 120120 Order* m_pOrder; 121121 }; 122122123123 //Director类,负责管理实例创建的依赖关系,指挥构建者类创建实例 124124 class Director 125125 { 126126 public: 127127 Director(OrderBuilder* builder) : m_pOrderBuilder(builder) 128128 { 129129 } 130130 void construct() 131131 { 132132 m_pOrderBuilder->setOrderFood(); 133133 m_pOrderBuilder->setOrderDrink(); 134134 } 135135136136 private: 137137 OrderBuilder* m_pOrderBuilder; 138138 }; 139139140140141141 int main() 142142 { 143143 // MeatOrderBuilder* mBuilder = new MeatOrderBuilder; 144144 OrderBuilder* mBuilder = new MeatOrderBuilder; //注意抽象构建类必须有虚析构函数,解析时才会 调用子类的析构函数 145145 Director* director = new Director(mBuilder); 146146 director->construct(); 147147 Order* order = mBuilder->getOrder(); 148148 order->food(); 149149 order->drink(); 150150151151 delete director; 152152 director = nullptr; 153153154154 delete mBuilder; 155155 mBuilder = nullptr; 156156157157 return 0; 158158 }

8、外观模式

外观模式:为子系统中的一组接口定义一个一致的界面;外观模式提供一个高层的接口,这个接口使得这一子系统更加容易被使用;对于复杂的系统,系统为客户端提供一个简单的接口,把负责的实现过程封装起来,客户端不需要连接系统内部的细节。

以下情形建议考虑外观模式:

  • 设计初期阶段,应有意识的将不同层分离,层与层之间建立外观模式。

  • 开发阶段,子系统越来越复杂,使用外观模式提供一个简单的调用接口。

  • 一个系统可能已经非常难易维护和扩展,但又包含了非常重要的功能,可以为其开发一个外观类,使得新系统可以方便的与其交互。

优点:

  • 实现了子系统与客户端之间的松耦合关系。

  • 客户端屏蔽了子系统组件,减少了客户端所需要处理的对象数据,使得子系统使用起来更方便容易。

  • 更好的划分了设计层次,对于后期维护更加的容易。

    1 /* 2 * 关键代码:客户与系统之间加一个外观层,外观层处理系统的调用关系、依赖关系等。 3 *以下实例以电脑的启动过程为例,客户端只关心电脑开机的、关机的过程,并不需要了解电脑内部子系统的启动过程。 4 */ 5 #include <iostream> 6 ​ 7 using namespace std; 8 ​ 9 //抽象控件类,提供接口 10 class Control 11 { 12 public: 13 virtual void start() = 0; 14 virtual void shutdown() = 0; 15 }; 16 ​ 17 //子控件, 主机 18 class Host : public Control 19 { 20 public: 21 void start() override 22 { 23 cout << "Host start" << endl; 24 } 25 void shutdown() override 26 { 27 cout << "Host shutdown" << endl; 28 } 29 }; 30 ​ 31 //子控件, 显示屏 32 class LCDDisplay : public Control 33 { 34 public: 35 void start() override 36 { 37 cout << "LCD Display start" << endl; 38 } 39 void shutdown() override 40 { 41 cout << "LCD Display shutdonw" << endl; 42 } 43 }; 44 ​ 45 //子控件, 外部设备 46 class Peripheral : public Control 47 { 48 public: 49 void start() override 50 { 51 cout << "Peripheral start" << endl; 52 } 53 void shutdown() override 54 { 55 cout << "Peripheral shutdown" << endl; 56 } 57 }; 58 ​ 59 class Computer 60 { 61 public: 62 void start() 63 { 64 m_host.start(); 65 m_display.start(); 66 m_peripheral.start(); 67 cout << "Computer start" << endl; 68 } 69 void shutdown() 70 { 71 m_host.shutdown(); 72 m_display.shutdown(); 73 m_peripheral.shutdown(); 74 cout << "Computer shutdown" << endl; 75 } 76 private: 77 Host m_host; 78 LCDDisplay m_display; 79 Peripheral m_peripheral; 80 }; 81 ​ 82 int main() 83 { 84 Computer computer; 85 computer.start(); 86 ​ 87 //do something 88 ​ 89 computer.shutdown(); 90 ​ 91 return 0; 92 }

9、组合模式

组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得客户端对单个对象和组合对象的使用具有一直性。

既然讲到以树形结构表示“部分-整体”,那可以将组合模式想象成一根大树,将大树分成树枝和树叶两部分,树枝上可以再长树枝,也可以长树叶,树叶上则不能再长出别的东西。

以下情况可以考虑使用组合模式:

  • 希望表示对象的部分-整体层次结构。

  • 希望客户端忽略组合对象与单个对象的不同,客户端将统一的使用组合结构中的所有对象。

    1 /* 2 * 关键代码:树枝内部组合该接口,并且含有内部属性list,里面放Component。 3 / 4 5 #include <iostream> 6 #include <list> 7 #include <memory> 8 9 using namespace std; 10 11 //抽象类,提供组合和单个对象的一致接口 12 class Company 13 { 14 public: 15 Company(const string& name): m_name(name){} 16 virtual ~Company(){ cout << "~Company()" << endl;} 17 18 virtual void add(Company ) = 0; 19 virtual void remove(const string&) = 0; 20 virtual void display(int depth) = 0; 21 22 virtual const string& name() 23 { 24 return m_name; 25 } 26 27 protected: 28 string m_name; 29 }; 30 31 //具体的单个对象实现类,“树枝”类 32 class HeadCompany : public Company 33 { 34 public: 35 HeadCompany(const string& name): Company(name){} 36 virtual ~HeadCompany(){ cout << "~HeadCompany()" << endl;} 37 38 void add(Company* company) override 39 { 40 shared_ptr<Company> temp(company); 41 m_companyList.push_back(temp); 42 } 43 44 void remove(const string& strName) override 45 { 46 list<shared_ptr<Company>>::iterator iter = m_companyList.begin(); 47 for(; iter != m_companyList.end(); iter++) 48 { 49 if((iter).get()->name() == strName) 50 { 51 //不应该在此处使用list<T>.erase(list<T>::iterator iter),会导致iter++错误,这里删除目 标元素之后,必须return。 52 m_companyList.erase(iter); 53 return; 54 } 55 } 56 } 57 58 void display(int depth) override 59 { 60 for(int i = 0; i < depth; i++) 61 { 62 cout << "-"; 63 } 64 cout << this->name().data() << endl; 65 list<shared_ptr<Company>>::iterator iter = m_companyList.begin(); 66 for(; iter!= m_companyList.end(); iter++) 67 { 68 (iter).get()->display(depth + 1); 69 } 70 } 71 72 private: 73 list<shared_ptr<Company>> m_companyList; 74 }; 75 76 //具体的单个对象实现类,“树叶”类 77 class ResearchCompany : public Company 78 { 79 public: 80 ResearchCompany(const string& name): Company(name){} 81 virtual ~ResearchCompany(){ cout << "~ResearchCompany()" << endl;} 82 83 void add(Company ) override 84 { 85 } 86 87 void remove(const string&) override 88 { 89 } 90 91 void display(int depth) override 92 { 93 for(int i = 0; i < depth; i++) 94 { 95 cout << "-"; 96 } 97 cout << m_name.data() << endl; 98 } 99 }; 100 101 //具体的单个对象实现类,“树叶”类 102 class SalesCompany : public Company 103 { 104 public: 105 SalesCompany(const string& name): Company(name){} 106 virtual ~SalesCompany(){ cout << "~SalesCompany()" << endl;} 107 108 void add(Company ) override 109 { 110 } 111 112 void remove(const string&) override 113 { 114 } 115 116 void display(int depth) override 117 { 118 for(int i = 0; i < depth; i++) 119 { 120 cout << "-"; 121 } 122 cout << m_name.data() << endl; 123 } 124 }; 125 126 //具体的单个对象实现类,“树叶”类 127 class FinanceCompany : public Company 128 { 129 public: 130 FinanceCompany(const string& name): Company(name){} 131 virtual ~FinanceCompany(){ cout << "~FinanceCompany()" << endl;} 132 133 void add(Company* ) override 134 { 135 } 136 137 void remove(const string&) override 138 { 139 } 140 141 void display(int depth) override 142 { 143 for(int i = 0; i < depth; i++) 144 { 145 cout << "-"; 146 } 147 cout << m_name.data() << endl; 148 } 149 }; 150 151 152 int main() 153 { 154 HeadCompany* headRoot = new HeadCompany("Head Root Company"); 155 156 HeadCompany* childRoot1 = new HeadCompany("Child Company A"); 157 ResearchCompany* r1 = new ResearchCompany("Research Company A"); 158 SalesCompany* s1 = new SalesCompany("Sales Company A"); 159 SalesCompany* s2 = new SalesCompany("Sales Company B"); 160 FinanceCompany* f1 = new FinanceCompany("FinanceCompany A"); 161
    162 childRoot1->add(r1); 163 childRoot1->add(s1); 164 childRoot1->add(s2); 165 childRoot1->add(f1); 166 167 HeadCompany* childRoot2 = new HeadCompany("Child Company B"); 168 ResearchCompany* r2 = new ResearchCompany("Research Company B"); 169 SalesCompany* s3 = new SalesCompany("Sales Company C"); 170 SalesCompany* s4 = new SalesCompany("Sales Company D"); 171 FinanceCompany* f2 = new FinanceCompany("FinanceCompany B"); 172
    173 childRoot2->add(r2); 174 childRoot2->add(s3); 175 childRoot2->add(s4); 176 childRoot2->add(f2); 177 178 headRoot->add(childRoot1); 179 headRoot->add(childRoot2); 180 headRoot->display(1); 181
    182 cout << "\n***************\n" << endl; 183 184 childRoot1->remove("Sales Company B"); 185 headRoot->display(1); 186
    187 cout << "\n***************\n" << endl; 188 189 delete headRoot; 190 headRoot = nullptr; 191 192 return 0; 193 }

10、代理模式

代理模式:为其它对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。

优点:

  • 职责清晰。真实的角色只负责实现实际的业务逻辑,不用关心其它非本职责的事务,通过后期的代理完成具体的任务。这样代码会简洁清晰。

  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样就保护了目标对象。

  • 扩展性好。

    1 /* 2 * 关键代码:一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理* 类再访问真正要访问的对象。 3 / 4 #include <iostream> 5 ​ 6 using namespace std; 7 ​ 8 class Gril 9 { 10 public: 11 Gril(const string& name = "gril"):m_string(name){} 12 string getName() 13 { 14 return m_string; 15 } 16 private: 17 string m_string; 18 }; 19 ​ 20 class Profession 21 { 22 public: 23 virtual ~Profession(){} 24 virtual void profess() = 0; 25 }; 26 ​ 27 class YoungMan : public Profession 28 { 29 public: 30 YoungMan(const Gril& gril):m_gril(gril){} 31 void profess() 32 { 33 cout << "Young man love " << m_gril.getName().data() << endl; 34 } 35 ​ 36 private: 37 Gril m_gril; 38 }; 39 ​ 40 class ManProxy : public Profession 41 { 42 public: 43 ManProxy(const Gril& gril):m_pMan(new YoungMan(gril)){} 44 ~ManProxy() 45 { 46 delete m_pMan; 47 m_pMan = nullptr; 48 } 49 void profess() 50 { 51 m_pMan->profess(); 52 } 53 private: 54 YoungMan m_pMan; 55 }; 56 ​ 57 int main(int argc, char argv[]) 58 { 59 Gril gril("heihei"); 60 ManProxy proxy = new ManProxy(gril); 61 proxy->profess(); 62 ​ 63 delete proxy; 64 proxy = nullptr; 65 return 0; 66 }

11、享元模式

享元模式:运用共享技术有效地支持大量细粒度的对象。在有大量对象时,把其中共同的部分抽象出来,如果有相同的业务请求,直接返回内存中已有的对象,避免重新创建。

以下情况可以考虑使用享元模式:

  • 系统中有大量的对象,这些对象消耗大量的内存,且这些对象的状态可以被外部化。

对于享元模式,需要将对象的信息分为两个部分:内部状态和外部状态。内部状态是指被共享出来的信息,储存在享元对象内部且不随环境变化而改变;外部状态是不可以共享的,它随环境改变而改变,是由客户端控制的。

1 1 /* 2 2 * 关键代码:将内部状态作为标识,进行共享。 3 3 */ 4 4 #include <iostream> 5 5 #include <map> 6 6 #include <memory> 7 78 8 using namespace std; 9 910 10 //抽象享元类,提供享元类外部接口。 11 11 class AbstractConsumer 12 12 { 13 13 public: 14 14 virtual ~AbstractConsumer(){} 15 15 virtual void setArticle(const string&) = 0; 16 16 virtual const string& article() = 0; 17 17 }; 18 1819 19 //具体的享元类 20 20 class Consumer : public AbstractConsumer 21 21 { 22 22 public: 23 23 Consumer(const string& strName) : m_user(strName){} 24 24 ~Consumer() 25 25 { 26 26 cout << " ~Consumer()" << endl; 27 27 } 28 2829 29 void setArticle(const string& info) override 30 30 { 31 31 m_article = info; 32 32 } 33 3334 34 const string& article() override 35 35 { 36 36 return m_article; 37 37 } 38 3839 39 private: 40 40 string m_user; 41 41 string m_article; 42 42 }; 43 4344 44 //享元工厂类 45 45 class Trusteeship 46 46 { 47 47 public: 48 48 ~Trusteeship() 49 49 { 50 50 m_consumerMap.clear(); 51 51 } 52 5253 53 void hosting(const string& user, const string& article) 54 54 { 55 55 if(m_consumerMap.count(user)) 56 56 { 57 57 cout << "A customer named " << user.data() << " already exists" << endl; 58 58 Consumer* consumer = m_consumerMap.at(user).get(); 59 59 consumer->setArticle(article); 60 60 } 61 61 else 62 62 { 63 63 shared_ptr<Consumer> consumer(new Consumer(user)); 64 64 consumer.get()->setArticle(article); 65 65 m_consumerMap.insert(pair<string, shared_ptr<Consumer>>(user, consumer)); 66 66 } 67 67 } 68 6869 69 void display() 70 70 { 71 71 map<string, shared_ptr<Consumer>>::iterator iter = m_consumerMap.begin(); 72 72 for(; iter != m_consumerMap.end(); iter++) 73 73 { 74 74 cout << iter->first.data() << " : "<< iter->second.get()->article().data() << endl; 75 75 } 76 76 } 77 7778 78 private: 79 79 map<string, shared_ptr<Consumer>> m_consumerMap; 80 80 }; 81 8182 8283 83 int main() 84 84 { 85 85 Trusteeship* ts = new Trusteeship; 86 86 ts->hosting("zhangsan", "computer"); 87 87 ts->hosting("lisi", "phone"); 88 88 ts->hosting("wangwu", "watch"); 89 8990 90 ts->display(); 91 9192 92 ts->hosting("zhangsan", "TT"); 93 93 ts->hosting("lisi", "TT"); 94 94 ts->hosting("wangwu", "TT"); 95 9596 96 ts->display(); 97 9798 98 delete ts; 99 99 ts = nullptr; 100100101101 return 0; 102102 }

12、桥接模式

桥接模式:将抽象部分与实现部分分离,使它们都可以独立变换。

以下情形考虑使用桥接模式:

  • 当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。

  • 当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来。

  • 当一个对象的多个变化因素可以动态变化的时候。

优点:

  • 将实现抽离出来,再实现抽象,使得对象的具体实现依赖于抽象,满足了依赖倒转原则。

  • 更好的可扩展性。

  • 可动态的切换实现。桥接模式实现了抽象和实现的分离,在实现桥接模式时,就可以实现动态的选择具体的实现。

    1 /* 2 * 关键代码:将现实独立出来,抽象类依赖现实类。 3 * 以下示例中,将各类App、各类手机独立开来,实现各种App和各种手机的自由桥接。 4 / 5 #include <iostream> 6 ​ 7 using namespace std; 8 ​ 9 //抽象App类,提供接口 10 class App 11 { 12 public: 13 virtual ~App(){ cout << "~App()" << endl; } 14 virtual void run() = 0; 15 }; 16 ​ 17 //具体的App实现类 18 class GameApp:public App 19 { 20 public: 21 void run() 22 { 23 cout << "GameApp Running" << endl; 24 } 25 }; 26 ​ 27 //具体的App实现类 28 class TranslateApp:public App 29 { 30 public: 31 void run() 32 { 33 cout << "TranslateApp Running" << endl; 34 } 35 }; 36 ​ 37 //抽象手机类,提供接口 38 class MobilePhone 39 { 40 public: 41 virtual ~MobilePhone(){ cout << "~MobilePhone()" << endl;} 42 virtual void appRun(App app) = 0; //实现App与手机的桥接 43 }; 44 ​ 45 //具体的手机实现类 46 class XiaoMi:public MobilePhone 47 { 48 public: 49 void appRun(App* app) 50 { 51 cout << "XiaoMi: "; 52 app->run(); 53 } 54 }; 55 ​ 56 //具体的手机实现类 57 class HuaWei:public MobilePhone 58 { 59 public: 60 void appRun(App* app) 61 { 62 cout << "HuaWei: "; 63 app->run(); 64 } 65 }; 66 ​ 67 int main() 68 { 69 App* gameApp = new GameApp; 70 App* translateApp = new TranslateApp; 71 MobilePhone* mi = new XiaoMi; 72 MobilePhone* hua = new HuaWei; 73 mi->appRun(gameApp); 74 mi->appRun(translateApp); 75 hua->appRun(gameApp); 76 hua->appRun(translateApp); 77 ​ 78 delete hua; 79 hua = nullptr; 80 delete mi; 81 mi = nullptr; 82 delete gameApp; 83 gameApp = nullptr; 84 delete translateApp; 85 translateApp = nullptr; 86 ​ 87 return 0; 88 }

13、装饰模式

装饰模式:动态地给一个对象添加一些额外的功能,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。新增加功能来说,装饰器模式比生产子类更加灵活。

以下情形考虑使用装饰模式:

  • 需要扩展一个类的功能,或给一个类添加附加职责。

  • 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

  • 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

    1 /* 2 * 关键代码:1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。 3 / 4 #include <iostream> 5 ​ 6 using namespace std; 7 ​ 8 //抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。 9 class Component 10 { 11 public: 12 virtual ~Component(){} 13 ​ 14 virtual void configuration() = 0; 15 }; 16 ​ 17 //具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。 18 class Car : public Component 19 { 20 public: 21 void configuration() override 22 { 23 cout << "A Car" << endl; 24 } 25 }; 26 ​ 27 //装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。 28 class DecorateCar : public Component 29 { 30 public: 31 DecorateCar(Component car) : m_pCar(car){} 32 ​ 33 void configuration() override 34 { 35 m_pCar->configuration(); 36 } 37 ​ 38 private: 39 Component* m_pCar; 40 }; 41 ​ 42 //具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。 43 class DecorateLED : public DecorateCar 44 { 45 public: 46 DecorateLED(Component* car) : DecorateCar(car){} 47 ​ 48 void configuration() override 49 { 50 DecorateCar::configuration(); 51 addLED(); 52 } 53 ​ 54 private: 55 void addLED() 56 { 57 cout << "Install LED" << endl; 58 } 59 ​ 60 }; 61 ​ 62 //具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。 63 class DecoratePC : public DecorateCar 64 { 65 public: 66 DecoratePC(Component* car) : DecorateCar(car){} 67 ​ 68 void configuration() override 69 { 70 DecorateCar::configuration(); 71 addPC(); 72 } 73 ​ 74 private: 75 void addPC() 76 { 77 cout << "Install PC" << endl; 78 } 79 }; 80 ​ 81 //具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。 82 class DecorateEPB : public DecorateCar 83 { 84 public: 85 DecorateEPB(Component* car) : DecorateCar(car){} 86 ​ 87 void configuration() override 88 { 89 DecorateCar::configuration(); 90 addEPB(); 91 } 92 ​ 93 private: 94 void addEPB() 95 { 96 cout << "Install Electrical Park Brake" << endl; 97 } 98 }; 99 ​ 100 int main() 101 { 102 Car* car = new Car; 103 DecorateLED* ledCar = new DecorateLED(car); 104 DecoratePC* pcCar = new DecoratePC(ledCar); 105 DecorateEPB* epbCar = new DecorateEPB(pcCar); 106 ​ 107 epbCar->configuration(); 108 ​ 109 delete epbCar; 110 epbCar = nullptr; 111 ​ 112 delete pcCar; 113 pcCar = nullptr; 114 ​ 115 delete ledCar; 116 ledCar = nullptr; 117 ​ 118 delete car; 119 car = nullptr; 120 ​ 121 return 0; 122 }

14、备忘录模式

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原来保存的状态。

备忘录模式中需要定义的角色类:

  1. Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。

  2. Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。

  3. Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。

    1 /* 2 * 关键代码:Memento类、Originator类、Caretaker类;Originator类不与Memento类耦合,而是与Caretaker类耦合。 3 */ 4 ​ 5 include <iostream> 6 ​ 7 using namespace std; 8 ​ 9 //需要保存的信息 10 typedef struct
    11 { 12 int grade; 13 string arm; 14 string corps; 15 }GameValue; 16 ​ 17 //Memento类 18 class Memento
    19 { 20 public: 21 Memento(){} 22 Memento(GameValue value):m_gameValue(value){} 23 GameValue getValue() 24 { 25 return m_gameValue; 26 } 27 private: 28 GameValue m_gameValue; 29 }; 30 ​ 31 //Originator类 32 class Game
    33 { 34 public: 35 Game(GameValue value):m_gameValue(value) 36 {} 37 void addGrade() //等级增加 38 { 39 m_gameValue.grade++; 40 } 41 void replaceArm(string arm) //更换武器 42 { 43 m_gameValue.arm = arm; 44 } 45 void replaceCorps(string corps) //更换工会 46 { 47 m_gameValue.corps = corps; 48 } 49 Memento saveValue() //保存当前信息 50 { 51 Memento memento(m_gameValue); 52 return memento; 53 } 54 void load(Memento memento) //载入信息 55 { 56 m_gameValue = memento.getValue(); 57 } 58 void showValue() 59 { 60 cout << "Grade: " << m_gameValue.grade << endl; 61 cout << "Arm : " << m_gameValue.arm.data() << endl; 62 cout << "Corps: " << m_gameValue.corps.data() << endl; 63 } 64 private: 65 GameValue m_gameValue; 66 }; 67 ​ 68 //Caretaker类 69 class Caretake 70 { 71 public: 72 void save(Memento memento) //保存信息 73 { 74 m_memento = memento; 75 } 76 Memento load() //读已保存的信息 77 { 78 return m_memento; 79 } 80 private: 81 Memento m_memento; 82 }; 83 ​ 84 int main() 85 { 86 GameValue v1 = {0, "Ak", "3K"}; 87 Game game(v1); //初始值 88 game.addGrade(); 89 game.showValue(); 90 cout << "----------" << endl; 91 Caretake care; 92 care.save(game.saveValue()); //保存当前值 93 game.addGrade(); //修改当前值 94 game.replaceArm("M16"); 95 game.replaceCorps("123"); 96 game.showValue(); 97 cout << "----------" << endl; 98 game.load(care.load()); //恢复初始值 99 game.showValue(); 100 return 0; 101 }

15、中介者模式

中介者模式:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之前的交互。

如果对象与对象之前存在大量的关联关系,若一个对象改变,常常需要跟踪与之关联的对象,并做出相应的处理,这样势必会造成系统变得复杂,遇到这种情形可以考虑使用中介者模式。当多个对象存在关联关系时,为它们设计一个中介对象,当一个对象改变时,只需要通知它的中介对象,再由它的中介对象通知每个与它相关的对象。

1 1 /* 2 2 * 关键代码:将相关对象的通信封装到一个类中单独处理。 3 3 */ 4 4 #include <iostream> 5 56 6 using namespace std; 7 78 8 class Mediator; 9 910 10 //抽象同事类。 11 11 class Businessman 12 12 { 13 13 public: 14 14 Businessman(){} 15 15 Businessman(Mediator* mediator) : m_pMediator(mediator){} 16 1617 17 virtual ~Businessman(){} 18 1819 19 virtual void setMediator(Mediator* m) 20 20 { 21 21 m_pMediator = m; 22 22 } 23 2324 24 virtual void sendMessage(const string& msg) = 0; 25 25 virtual void getMessage(const string& msg) = 0; 26 2627 27 protected: 28 28 Mediator* m_pMediator; 29 29 }; 30 3031 31 //抽象中介者类。 32 32 class Mediator 33 33 { 34 34 public: 35 35 virtual ~Mediator(){} 36 36 virtual void setBuyer(Businessman* buyer) = 0; 37 37 virtual void setSeller(Businessman* seller) = 0; 38 38 virtual void send(const string& msg, Businessman* man) = 0; 39 39 }; 40 4041 41 //具体同事类 42 42 class Buyer : public Businessman 43 43 { 44 44 public: 45 45 Buyer() : Businessman(){} 46 46 Buyer(Mediator* mediator) : Businessman(mediator){} 47 4748 48 void sendMessage(const string& msg) override 49 49 { 50 50 m_pMediator->send(msg, this); 51 51 } 52 5253 53 void getMessage(const string& msg) 54 54 { 55 55 cout << "Buyer recv: " << msg.data() << endl; 56 56 } 57 57 }; 58 5859 59 //具体同事类 60 60 class Seller : public Businessman 61 61 { 62 62 public: 63 63 Seller() : Businessman(){} 64 64 Seller(Mediator* mediator) : Businessman(mediator){} 65 6566 66 void sendMessage(const string& msg) override 67 67 { 68 68 m_pMediator->send(msg, this); 69 69 } 70 7071 71 void getMessage(const string& msg) 72 72 { 73 73 cout << "Seller recv: " << msg.data() << endl; 74 74 } 75 75 }; 76 7677 77 //具体中介者类 78 78 class HouseMediator : public Mediator 79 79 { 80 80 public: 81 81 void setBuyer(Businessman* buyer) override 82 82 { 83 83 m_pBuyer = buyer; 84 84 } 85 8586 86 void setSeller(Businessman* seller) override 87 87 { 88 88 m_pSeller = seller; 89 89 } 90 9091 91 void send(const string& msg, Businessman* man) override 92 92 { 93 93 if(man == m_pBuyer) 94 94 { 95 95 m_pSeller->getMessage(msg); 96 96 } 97 97 else if(man == m_pSeller) 98 98 { 99 99 m_pBuyer->getMessage(msg); 100100 } 101101 } 102102103103 private: 104104 Businessman* m_pBuyer; 105105 Businessman* m_pSeller; 106106 }; 107107108108 int main() 109109 { 110110 HouseMediator* hMediator = new HouseMediator; 111111 Buyer* buyer = new Buyer(hMediator); 112112 Seller* seller = new Seller(hMediator); 113113114114 hMediator->setBuyer(buyer); 115115 hMediator->setSeller(seller); 116116117117 buyer->sendMessage("Sell not to sell?"); 118118 seller->sendMessage("Of course selling!"); 119119120120 delete buyer; 121121 buyer = nullptr; 122122123123 delete seller; 124124 seller = nullptr; 125125126126 delete hMediator; 127127 hMediator = nullptr; 128128129129130130 return 0; 131131 }

16、职责链模式

职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之前的耦合关系,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递,所有职责链将请求的发送者和请求的处理者解耦了。

1 1 /* 2 2 * 关键代码:Handler内指明其上级,handleRequest()里判断是否合适,不合适则传递给上级。 3 3 */ 4 4 #include <iostream> 5 56 6 using namespace std; 7 78 8 enum RequestLevel 9 9 { 1010 Level_One = 0, 1111 Level_Two, 1212 Level_Three, 1313 Level_Num 1414 }; 15151616 //抽象处理者(Handler)角色,提供职责链的统一接口。 1717 class Leader 1818 { 1919 public: 2020 Leader(Leader* leader):m_leader(leader){} 2121 virtual ~Leader(){} 2222 virtual void handleRequest(RequestLevel level) = 0; 2323 protected: 2424 Leader* m_leader; 2525 }; 26262727 //具体处理者(Concrete Handler)角色 2828 class Monitor:public Leader //链扣1 2929 { 3030 public: 3131 Monitor(Leader* leader):Leader(leader){} 3232 void handleRequest(RequestLevel level) 3333 { 3434 if(level < Level_Two) 3535 { 3636 cout << "Mointor handle request : " << level << endl; 3737 } 3838 else 3939 { 4040 m_leader->handleRequest(level); 4141 } 4242 } 4343 }; 44444545 //具体处理者(Concrete Handler)角色 4646 class Captain:public Leader //链扣2 4747 { 4848 public: 4949 Captain(Leader* leader):Leader(leader){} 5050 void handleRequest(RequestLevel level) 5151 { 5252 if(level < Level_Three) 5353 { 5454 cout << "Captain handle request : " << level << endl; 5555 } 5656 else 5757 { 5858 m_leader->handleRequest(level); 5959 } 6060 } 6161 }; 62626363 //具体处理者(Concrete Handler)角色 6464 class General:public Leader //链扣3 6565 { 6666 public: 6767 General(Leader* leader):Leader(leader){} 6868 void handleRequest(RequestLevel level) 6969 { 7070 cout << "General handle request : " << level << endl; 7171 } 7272 }; 73737474 int main() 7575 { 7676 Leader* general = new General(nullptr); 7777 Leader* captain = new Captain(general); 7878 Leader* monitor = new Monitor(captain); 7979 monitor->handleRequest(Level_One); 80808181 delete monitor; 8282 monitor = nullptr; 8383 delete captain; 8484 captain = nullptr; 8585 delete general; 8686 general = nullptr; 8787 return 0; 8888 }

17、观察者模式

观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都要得到通知并自动更新。

观察者模式从根本上讲必须包含两个角色:观察者和被观察对象。

  • 被观察对象自身应该包含一个容器来存放观察者对象,当被观察者自身发生改变时通知容器内所有的观察者对象自动更新。

  • 观察者对象可以注册到被观察者的中,完成注册后可以检测被观察者的变化,接收被观察者的通知。当然观察者也可以被注销掉,停止对被观察者的监控。

    1 /* 2 * 关键代码:在目标类中增加一个ArrayList来存放观察者们。 3 / 4 #include <iostream> 5 #include <list> 6 #include <memory> 7 ​ 8 using namespace std; 9 ​ 10 class View; 11 ​ 12 //被观察者抽象类 数据模型 13 class DataModel 14 { 15 public: 16 virtual ~DataModel(){} 17 virtual void addView(View view) = 0; 18 virtual void removeView(View* view) = 0; 19 virtual void notify() = 0; //通知函数 20 }; 21 ​ 22 //观察者抽象类 视图 23 class View 24 { 25 public: 26 virtual ~View(){ cout << "~View()" << endl; } 27 virtual void update() = 0; 28 virtual void setViewName(const string& name) = 0; 29 virtual const string& name() = 0; 30 }; 31 ​ 32 //具体的被观察类, 整数模型 33 class IntDataModel:public DataModel 34 { 35 public: 36 ~IntDataModel() 37 { 38 m_pViewList.clear(); 39 } 40 ​ 41 virtual void addView(View* view) override 42 { 43 shared_ptr<View> temp(view); 44 auto iter = find(m_pViewList.begin(), m_pViewList.end(), temp); 45 if(iter == m_pViewList.end()) 46 { 47 m_pViewList.push_front(temp); 48 } 49 else 50 { 51 cout << "View already exists" << endl; 52 } 53 } 54 ​ 55 void removeView(View* view) override 56 { 57 auto iter = m_pViewList.begin(); 58 for(; iter != m_pViewList.end(); iter++) 59 { 60 if((iter).get() == view) 61 { 62 m_pViewList.erase(iter); 63 cout << "remove view" << endl; 64 return; 65 } 66 } 67 } 68 ​ 69 virtual void notify() override 70 { 71 auto iter = m_pViewList.begin(); 72 for(; iter != m_pViewList.end(); iter++) 73 { 74 (iter).get()->update(); 75 } 76 } 77 ​ 78 private: 79 list<shared_ptr<View>> m_pViewList; 80 }; 81 ​ 82 //具体的观察者类 表视图 83 class TableView : public View 84 { 85 public: 86 TableView() : m_name("unknow"){} 87 TableView(const string& name) : m_name(name){} 88 ~TableView(){ cout << "~TableView(): " << m_name.data() << endl; } 89 ​ 90 void setViewName(const string& name) 91 { 92 m_name = name; 93 } 94 ​ 95 const string& name() 96 { 97 return m_name; 98 } 99 ​ 100 void update() override 101 { 102 cout << m_name.data() << " update" << endl; 103 } 104 ​ 105 private: 106 string m_name; 107 }; 108 ​ 109 int main() 110 { 111 / 112 * 这里需要补充说明的是在此示例代码中,View一旦被注册到DataModel类之后,DataModel解析时会自动解析掉 * 内部容器中存储的View对象,因此注册后的View对象不需要在手动去delete,再去delete View对象会出错。 113 / 114
    115 View
    v1 = new TableView("TableView1"); 116 View
    v2 = new TableView("TableView2"); 117 View* v3 = new TableView("TableView3"); 118 View* v4 = new TableView("TableView4"); 119 ​ 120 IntDataModel* model = new IntDataModel; 121 model->addView(v1); 122 model->addView(v2); 123 model->addView(v3); 124 model->addView(v4); 125 ​ 126 model->notify(); 127 ​ 128 cout << "-------------\n" << endl; 129 ​ 130 model->removeView(v1); 131 ​ 132 model->notify(); 133 ​ 134 delete model; 135 model = nullptr; 136 ​ 137 return 0; 138 } 139 ​

注:原文是2018年初写的,2019年6月11日修改。如有错误欢迎指正。

点赞
收藏

评论区

加载中...

相关推荐

笑说设计模式-小白逃课被点名

关于我简介工厂模式(FactoryPattern)是最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。分类工厂模式可以分为三种,其中简单工厂一般不被认为是一种设计模式,可以将其看成是工厂方法的一种特殊

创建型-工厂模式 ( Factory Pattern )

创建型工厂模式(FactoryPattern)tex工厂模式(FactoryPattern)提供了一种创建对象的最佳方式工厂模式在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象工厂

Java设计模式之三种工厂模式

工厂模式实现了创建者和调用者的分离,实现了更好的解耦。详细分类:1)简单工厂模式(静态工厂模式);2)工厂方法模式;3)抽象工厂模式面向对象设计的基本原则:1)      OCP(开闭原则,OpenClosedPrinciple):一个软件的实体应当对扩展开放,对修改关闭。2)      

Unity C# 设计模式(二)简单工厂模式

定义:简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactoryMethod)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该

C#简单工厂模式

C简单工厂模式模型,建立一个模型,构建我们的实际工程,项目。​所有面向对象的编程都是在我们生活中存在的,从词义的解释就是我们生活中的工厂就是负责生产产品的,而到开发中对应的就是NEW不同的对象,该模式主要解决的问题就是解决创建对象与该类的解耦。设计原则中经常说的类单一职责、封装性都有体现。编程中的简单工厂就是一个生产

Java描述设计模式(04):抽象工厂模式

一、抽象工厂模式1、生活场景汽车生产根据用户选择的汽车类型,指定不同的工厂进行生产,选择红旗轿车,就要使用中国工厂,选择奥迪轿车,就要使用德国工厂。2、抽象工厂模式1.抽象工厂模式:定义了一个interface用于创建相关对象或相互依赖的对象,而无需指明具体的类;2.抽象工厂模式可以