设计模式 c++

1、工厂模式

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

1.1、简单工厂模式

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

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

/*
 2 关键代码:创建过程在工厂类中完成。
 3 */
 45 #include <iostream>
 67 using namespace std;
 89 //定义产品类型信息
10 typedef enum
11 {
12     Tank_Type_56,
13     Tank_Type_96,
14     Tank_Type_Num
15 }Tank_Type;
1617 //抽象产品类
18 class Tank
19 {
20 public:
21     virtual const string& type() = 0;
22 };
2324 //具体的产品类
25 class Tank56 : public Tank
26 {
27 public:
28     Tank56():Tank(),m_strType("Tank56")
29     {
30     }
3132     const string& type() override
33     {
34         cout << m_strType.data() << endl;
35         return m_strType;
36     }
37 private:
38     string m_strType;
39 };
4041 //具体的产品类
42 class Tank96 : public Tank
43 {
44 public:
45     Tank96():Tank(),m_strType("Tank96")
46     {
47     }
48     const string& type() override
49     {
50         cout << m_strType.data() << endl;
51         return m_strType;
52     }
5354 private:
55     string m_strType;
56 }; 
5758 //工厂类
59 class TankFactory
60 {
61 public:
62     //根据产品信息创建具体的产品类实例,返回一个抽象产品类
63     Tank* createTank(Tank_Type type)
64     {
65         switch(type)
66         {
67         case Tank_Type_56:
68             return new Tank56();
69         case Tank_Type_96:
70             return new Tank96();
71         default:
72             return nullptr;
73         }
74     }
75 };
767778 int main()
79 {
80     TankFactory* factory = new TankFactory();
81     Tank* tank56 = factory->createTank(Tank_Type_56);
82     tank56->type();
83     Tank* tank96 = factory->createTank(Tank_Type_96);
84     tank96->type();
8586     delete tank96;
87     tank96 = nullptr;
88     delete tank56;
89     tank56 = nullptr;
90     delete factory;
91     factory = nullptr;
9293     return 0;
94 }

1.2、工厂方法模式

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

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

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

1.3、抽象工厂模式

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

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

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

1 /*
  2 * 关键代码:在一个工厂里聚合多个同类产品。
  3 * 以下代码以白色衣服和黑色衣服为例,白色衣服为一个产品系列,黑色衣服为一个产品系列。白色上衣搭配白色裤子,   黑色上衣搭配黑色裤字。每个系列的衣服由一个对应的工厂创建,这样一个工厂创建的衣服能保证衣服为同一个系列。
  4 */
  56 //抽象上衣类
  7 class Coat
  8 {
  9 public:
 10     virtual const string& color() = 0;
 11 };
 1213 //黑色上衣类
 14 class BlackCoat : public Coat
 15 {
 16 public:
 17     BlackCoat():Coat(),m_strColor("Black Coat")
 18     {
 19     }
 2021     const string& color() override
 22     {
 23         cout << m_strColor.data() << endl;
 24         return m_strColor;
 25     }
 26 private:
 27     string m_strColor;
 28 };
 2930 //白色上衣类
 31 class WhiteCoat : public Coat
 32 {
 33 public:
 34     WhiteCoat():Coat(),m_strColor("White Coat")
 35     {
 36     }
 37     const string& color() override
 38     {
 39         cout << m_strColor.data() << endl;
 40         return m_strColor;
 41     }
 4243 private:
 44     string m_strColor;
 45 }; 
 4647 //抽象裤子类
 48 class Pants
 49 {
 50 public:
 51     virtual const string& color() = 0;
 52 };
 5354 //黑色裤子类
 55 class BlackPants : public Pants
 56 {
 57 public:
 58     BlackPants():Pants(),m_strColor("Black Pants")
 59     {
 60     }
 61     const string& color() override
 62     {
 63         cout << m_strColor.data() << endl;
 64         return m_strColor;
 65     }
 6667 private:
 68     string m_strColor;
 69 };
 7071 //白色裤子类
 72 class WhitePants : public Pants
 73 {
 74 public:
 75     WhitePants():Pants(),m_strColor("White Pants")
 76     {
 77     }
 78     const string& color() override
 79     {
 80         cout << m_strColor.data() << endl;
 81         return m_strColor;
 82     }
 8384 private:
 85     string m_strColor;
 86 };
 8788 //抽象工厂类,提供衣服创建接口
 89 class Factory
 90 {
 91 public:
 92     //上衣创建接口,返回抽象上衣类
 93     virtual Coat* createCoat() = 0;
 94     //裤子创建接口,返回抽象裤子类
 95     virtual Pants* createPants() = 0;
 96 };
 9798 //创建白色衣服的工厂类,具体实现创建白色上衣和白色裤子的接口
 99 class WhiteFactory : public Factory
100 {
101 public:
102     Coat* createCoat() override
103     {
104         return new WhiteCoat();
105     }
106107     Pants* createPants() override
108     {
109         return new WhitePants();
110     }
111 };
112113 //创建黑色衣服的工厂类,具体实现创建黑色上衣和白色裤子的接口
114 class BlackFactory : public Factory
115 {
116     Coat* createCoat() override
117     {
118         return new BlackCoat();
119     }
120121     Pants* createPants() override
122     {
123         return new BlackPants();
124     }
125 };

2、策略模式

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

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

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

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

2.1、传统的策略模式实现

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

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

#include <iostream>
 2 #include <functional> 
 34 void adcHurt()
 5 {
 6     std::cout << "Adc Hurt" << std::endl;
 7 }
 89 void apcHurt()
10 {
11     std::cout << "Apc Hurt" << std::endl;
12 }
1314 //环境角色类, 使用传统的函数指针
15 class Soldier
16 {
17 public:
18     typedef void (*Function)();
19     Soldier(Function fun): m_fun(fun)
20     {
21     }
22     void attack()
23     {
24         m_fun();
25     }
26 private:
27     Function m_fun;
28 };
2930 //环境角色类, 使用std::function<>
31 class Mage
32 {
33 public:
34     typedef std::function<void()> Function;
3536     Mage(Function fun): m_fun(fun)
37     {
38     }
39     void attack()
40     {
41         m_fun();
42     }
43 private:
44     Function m_fun;
45 };
4647 int main()
48 {
49     Soldier* soldier = new Soldier(apcHurt);
50     soldier->attack();
51     delete soldier;
52     soldier = nullptr;
53     return 0;
54 }

3、适配器模式

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

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

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

 1 /*
 2 * 关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。
 3 * 以下示例中,假设我们之前有了一个双端队列,新的需求要求使用栈和队列来完成。
 4   双端队列可以在头尾删减或增加元素。而栈是一种先进后出的数据结构,添加数据时添加到栈的顶部,删除数据时先删   除栈顶部的数据。因此我们完全可以将一个现有的双端队列适配成一个栈。
 5 */
 67 //双端队列, 被适配类
 8 class Deque
 9 {
10 public:
11     void push_back(int x)
12     {
13         cout << "Deque push_back:" << x << endl;
14     }
15     void push_front(int x)
16     {
17         cout << "Deque push_front:" << x << endl;
18     }
19     void pop_back()
20     {
21         cout << "Deque pop_back" << endl;
22     }
23     void pop_front()
24     {
25         cout << "Deque pop_front" << endl;
26     }
27 };
2829 //顺序类,抽象目标类
30 class Sequence  
31 {
32 public:
33     virtual void push(int x) = 0;
34     virtual void pop() = 0;
35 };
3637 //栈,后进先出, 适配类
38 class Stack:public Sequence   
39 {
40 public:
41     //将元素添加到堆栈的顶部。
42     void push(int x) override
43     {
44         m_deque.push_front(x);
45     }
46     //从堆栈中删除顶部元素
47     void pop() override
48     {
49         m_deque.pop_front();
50     }
51 private:
52     Deque m_deque;
53 };
5455 //队列,先进先出,适配类
56 class Queue:public Sequence  
57 {
58 public:
59     //将元素添加到队列尾部
60     void push(int x) override
61     {
62         m_deque.push_back(x);
63     }
64     //从队列中删除顶部元素
65     void pop() override
66     {
67         m_deque.pop_front();
68     }
69 private:
70     Deque m_deque;
71 };

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

1 //双端队列,被适配类
 2 class Deque  
 3 {
 4 public:
 5     void push_back(int x)
 6     {
 7         cout << "Deque push_back:" << x << endl;
 8     }
 9     void push_front(int x)
10     {
11         cout << "Deque push_front:" << x << endl;
12     }
13     void pop_back()
14     {
15         cout << "Deque pop_back" << endl;
16     }
17     void pop_front()
18     {
19         cout << "Deque pop_front" << endl;
20     }
21 };
2223 //顺序类,抽象目标类
24 class Sequence  
25 {
26 public:
27     virtual void push(int x) = 0;
28     virtual void pop() = 0;
29 };
3031 //栈,后进先出, 适配类
32 class Stack:public Sequence, private Deque   
33 {
34 public:
35     void push(int x)
36     {
37         push_front(x);
38     }
39     void pop()
40     {
41         pop_front();
42     }
43 };
4445 //队列,先进先出,适配类
46 class Queue:public Sequence, private Deque 
47 {
48 public:
49     void push(int x)
50     {
51         push_back(x);
52     }
53     void pop()
54     {
55         pop_front();
56     }
57 };

4、单例模式

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

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

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

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

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

4.1、懒汉单例模式

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

1 /*
 2 * 关键代码:构造函数是私有的,不能通过赋值运算,拷贝构造等方式实例化对象。
 3 */
 45 //懒汉式一般实现:非线程安全,getInstance返回的实例指针需要delete
 6 class Singleton
 7 {
 8 public:
 9     static Singleton* getInstance();
10     ~Singleton(){}
1112 private:
13     Singleton(){}                                        //构造函数私有
14     Singleton(const Singleton& obj) = delete;            //明确拒绝
15     Singleton& operator=(const Singleton& obj) = delete; //明确拒绝
16     
17     static Singleton* m_pSingleton;
18 };
1920 Singleton* Singleton::m_pSingleton = NULL;
2122 Singleton* Singleton::getInstance()
23 {
24     if(m_pSingleton == NULL)
25     {
26         m_pSingleton = new Singleton;
27     }
28     return m_pSingleton;
29 }

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

1 std::mutex mt;
 2 
 3 class Singleton
 4 {
 5 public:
 6     static Singleton* getInstance();
 7 private:
 8     Singleton(){}                                    //构造函数私有
 9     Singleton(const Singleton&) = delete;            //明确拒绝
10     Singleton& operator=(const Singleton&) = delete; //明确拒绝
11 
12     static Singleton* m_pSingleton;
13     
14 };
15 Singleton* Singleton::m_pSingleton = NULL;
16 
17 Singleton* Singleton::getInstance()
18 {
19     if(m_pSingleton == NULL)
20     {
21         const std::lock_guard<std::mutex> lock(mt);
22         if(m_pSingleton == NULL)
23         {
24             m_pSingleton = new Singleton();
25         }
26         //mt.unlock();
27     }
28     return m_pSingleton;
29 }

上述的方式可能会有意料不到的后果。问题的来源是CPU的乱序执行,C++的New操作实际上包含了两个步骤:(1)分配内存;(2)调用构造函数。

实际上,m_pSingleton = new Singleton();

包含了三个步骤:

(1)分配内存
(2)在内存的位置上调用构造函数
(3)将内存的地址赋值给pInst
因为(2)和(3)是可以颠倒的,所以可以出现这样的情况:m_pSingleton的值已经不是NULL,但对象仍然没有构造完毕。如果另外一个线程对GetInstance的调用,此时第一个if为false,这样就会返回一个未构造完成的对象,此时可能会导致程序崩溃
解决思路:用局部变量过度一下:

Singleton* Singleton::getInstance()
{
    if(m_pSingleton == NULL)
     {
         const std::lock_guard<std::mutex> lock(mt);
         if(m_pSingleton == NULL)
         {
             Singleton* tmp = new Singleton();
             m_pSingleton = tmp;
         }
         //mt.unlock();
     }
     return m_pSingleton;
}        

补充: 这里为什么要判断两次 m_pSingleton == NUL ?

答:多个线程在接触到第一次判断时,m_pSingleton都为空。那么除了第一个拿到锁的进程, 其他进程都挂起了。当第一个拿到锁的进程结束之后,后续挂起的程序会依次执行,这个时候如果不再加一个非空判断的话,会多次构造m_pSingleton

4.2、饿汉单例模式

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

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

5、原型模式

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

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

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

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

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

/*
 2 * 关键代码:拷贝,return new className(*this);
 3 */
 4 #include <iostream>
 56 using namespace std;
 78 //提供一个抽象克隆基类。
 9 class Clone
10 {
11 public:
12     virtual Clone* clone() = 0;
13     virtual void show() = 0;
14 };
1516 //具体的实现类
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 };
5152 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 /*
 2 * 关键代码:在抽象类实现通用接口,细节变化在子类实现。
 3 */
 45 #include <iostream>
 67 using namespace std;
 89 class Computer
10 {
11 public:
12     void product()
13     {
14         installCpu();
15         installRam();
16         installGraphicsCard();
17     }
1819 protected:
20     virtual void installCpu() = 0;
21     virtual void installRam() = 0;
22     virtual void installGraphicsCard() = 0;
2324 };
2526 class ComputerA : public Computer
27 {
28 protected:
29     void installCpu() override
30     {
31         cout << "ComputerA install Inter Core i5" << endl;
32     }
3334     void installRam() override
35     {
36         cout << "ComputerA install 2G Ram" << endl;
37     }
3839     void installGraphicsCard() override
40     {
41         cout << "ComputerA install Gtx940 GraphicsCard" << endl;
42     }
43 };
4445 class ComputerB : public Computer
46 {
47 protected:
48     void installCpu() override
49     {
50         cout << "ComputerB install Inter Core i7" << endl;
51     }
5253     void installRam() override
54     {
55         cout << "ComputerB install 4G Ram" << endl;
56     }
5758     void installGraphicsCard() override
59     {
60         cout << "ComputerB install Gtx960 GraphicsCard" << endl;
61     }
62 };
6364 int main()
65 {
66     ComputerB* c1 = new ComputerB();
67     c1->product();
6869     delete c1;
70     c1 = nullptr;
7172     return 0;
73 }

7、建造者模式

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

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

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

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

建造者模式的优点:

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

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

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

1 /*
  2 *关键代码:建造者类:创建和提供实例; Director类:管理建造出来的实例的依赖关系。
  3 */
  45 #include <iostream>
  6 #include <string>
  78 using namespace std;
  910 //具体的产品类
 11 class Order
 12 {
 13 public:
 14     void setFood(const string& food)
 15     {
 16         m_strFood = food;
 17     }
 1819     const string& food()
 20     {
 21         cout << m_strFood.data() << endl;
 22         return m_strFood;
 23     }
 24     
 25     void setDrink(const string& drink)
 26     {
 27         m_strDrink = drink;
 28     }
 2930     const string& drink()
 31     {
 32         cout << m_strDrink << endl;
 33         return m_strDrink;
 34     }
 3536 private:
 37     string m_strFood;
 38     string m_strDrink;
 39 };
 4041 //抽象建造类,提供建造接口。
 42 class OrderBuilder
 43 {
 44 public:
 45     virtual ~OrderBuilder()
 46     {
 47         cout << "~OrderBuilder()" << endl;
 48     }
 49     virtual void setOrderFood() = 0;
 50     virtual void setOrderDrink() = 0;
 51     virtual Order* getOrder() = 0;
 52 };
 5354 //具体的建造类
 55 class VegetarianOrderBuilder : public OrderBuilder 
 56 {
 57 public:
 58     VegetarianOrderBuilder()
 59     {
 60         m_pOrder = new Order;
 61     }
 6263     ~VegetarianOrderBuilder()
 64     {
 65         cout << "~VegetarianOrderBuilder()" << endl;
 66         delete m_pOrder;
 67         m_pOrder = nullptr;
 68     }
 6970     void setOrderFood() override
 71     {
 72         m_pOrder->setFood("vegetable salad");
 73     }
 7475     void setOrderDrink() override
 76     {
 77         m_pOrder->setDrink("water");
 78     }
 7980     Order* getOrder() override
 81     {
 82         return m_pOrder;
 83     }
 8485 private:
 86     Order* m_pOrder;
 87 };
 8889 //具体的建造类
 90 class MeatOrderBuilder : public OrderBuilder
 91 {
 92 public:
 93     MeatOrderBuilder()
 94     {
 95         m_pOrder = new Order;
 96     }
 97     ~MeatOrderBuilder()
 98     {
 99         cout << "~MeatOrderBuilder()" << endl;
100         delete m_pOrder;
101         m_pOrder = nullptr;
102     }
103104     void setOrderFood() override
105     {
106         m_pOrder->setFood("beef");
107     }
108109     void setOrderDrink() override
110     {
111         m_pOrder->setDrink("beer");
112     }
113114     Order* getOrder() override
115     {
116         return m_pOrder;
117     }
118119 private:
120     Order* m_pOrder;
121 };
122123 //Director类,负责管理实例创建的依赖关系,指挥构建者类创建实例
124 class Director
125 {
126 public:
127     Director(OrderBuilder* builder) : m_pOrderBuilder(builder)
128     {
129     }
130     void construct()
131     {
132         m_pOrderBuilder->setOrderFood();
133         m_pOrderBuilder->setOrderDrink();
134     }
135136 private:
137     OrderBuilder* m_pOrderBuilder;
138 };
139140141 int main()
142 {
143 //  MeatOrderBuilder* mBuilder = new MeatOrderBuilder;
144     OrderBuilder* mBuilder = new MeatOrderBuilder;  //注意抽象构建类必须有虚析构函数,解析时才会                                                      调用子类的析构函数
145     Director* director = new Director(mBuilder);
146     director->construct();
147   Order* order = mBuilder->getOrder();
148   order->food();
149   order->drink();
150151   delete director;
152   director = nullptr;
153154   delete mBuilder;
155   mBuilder = nullptr;
156157   return 0;
158 }

 

7、访问者模式(visitor pattern)

定义: 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作 。

(补充一下应用的场景) 

https://www.cnblogs.com/chengjundu/p/8473564.html

https://blog.csdn.net/ShuSheng0007/article/details/115980889 (相关设计模式的一个大致介绍,分类去梳理,可能效果更好一些) (构建模式、 行为模式、 命令模式)

posted @ 2021-09-26 09:55  猪突猛进!!!  阅读(50)  评论(0编辑  收藏  举报