設計模式——創建型設計模式總結(簡單工廠、普通工廠、抽象工廠、建造者、原型和單例)

創建型設計模式總結

(轉載請註明來源 http://www.cnblogs.com/jerry19880126/

創建型設計模式包括簡單工廠模式,普通工廠模式,抽象工廠模式,建造者模式,原型模式和最簡單的單例模式。

 

簡單工廠模式(Simple Factory)

 

從UML圖中可以看出,(UML類圖關係可參考 http://blog.csdn.net/cc198877/article/details/8853110),工廠是具體的,Product是抽象的,裏面的方法Operation是virtual的,它的三個子類是具體的,子類中的Operation覆蓋父類的方法Operation,由多態知識可知,運行時將會調用子類的Operation,父類的Operation只是聲明的“接口”。

多態有三個條件:一是父類的virtual,二是子類的覆蓋(要求函數名、參數、返回值都要一模一樣),三是父類的指針或引用指向子類的對象。前兩個條件已經滿足,下面關鍵是討論第三個條件。

第三個條件的關鍵就是Factory了,Factory能根據客戶端的請求,生成不同的具體對象,這可以用flag來標識,假定flag = 1時,生成ConcreteProduct1對象;flag = 2時,生成ConcreteProduct2對象。因此,可以在Factory這樣寫CreateProduct()。

Product* CreateProduct(flag)

{

Switch(flag)

case 1: return new ConcreateProduct1(); break;

case 2: return new ConcreateProduct2(); break;

case 3:…

}

 

在客戶端只要用

Factory f; // 生成factory對象

f.getProduct(1).Operation();就可以調用ConcreteProduct1的方法了

f.getProduct(2).Operation();就可以調用ConcreteProudct2的方法了。

 

這樣說來,相信讀者已經明白,其實工廠方法就是根據客戶端不同的“要求”,產生不同的具體對象,再利用多態特性,調用相應具體對象的方法。

 

下面給出可執行的源代碼,與上述例子不盡相同,但思想是一樣的,運行結果如下圖所示。

簡單工廠模式
複製代碼
 1 #include <iostream>
 2 using namespace std;
 3 
 4 // 簡單工廠模式
 5 
 6 // 抽象產品
 7 class AbstractProduct
 8 {
 9 public:
10     virtual void getProductsName() = 0;
11 };
12 
13 // 具體產品1
14 class ConcreteProduct1: public AbstractProduct
15 {
16 public:
17     void  getProductsName()
18     {
19         cout << "ConcreteProduct1" << endl;
20     }
21 };
22 
23 
24 // 具體產品2
25 class ConcreteProduct2: public AbstractProduct
26 {
27 public:
28     void  getProductsName()
29     {
30         cout << "ConcreteProduct2" << endl;
31     }
32 };
33 
34 
35 // 具體的工廠(沒有抽象工廠)
36 class ConcreteFactory
37 {
38 public:
39     AbstractProduct* getProductObject(int flag)
40     {
41         if(flag == 1)
42         {
43             return new ConcreteProduct1();
44         }
45         else if(flag == 2)
46         {
47             return new ConcreteProduct2();
48         }
49         else
50         {
51             return 0;
52         }
53     }
54 };
55 
56 int main()
57 {
58     ConcreteFactory f;
59     AbstractProduct* p1 = f.getProductObject(1);
60     AbstractProduct* p2 = f.getProductObject(2);
61     p1->getProductsName();
62     p2->getProductsName();
63     delete p1;
64     delete p2;
65     return 0;
66 }
複製代碼

 

運行結果如下:

 

(普通)工廠模式(Factory)

與簡單工廠模式換湯不換藥,只是把工廠也“抽象”了,UML圖如下所示:

 

從上圖可以看出,只不過多出一塊抽象工廠而已。抽象工廠提供CreateProduct的虛接口,在ConcreteFactory中實現,爲了便於說明問題,這裏假定有兩個ConcreteFactory,一個是ConcreteFactory1,只生產ConcreteProduct1產品,另一個是ConcreteFactory2,只生產ConcreteProduct2產品。

 

以ConcreteFactory1爲例,代碼框架如下:

class ConcreateFactory1: public Factory

{

 Product* CreateProduct()

{

     return new ConcreteProduct1();

}

};

 

在客戶端用 Factory *f = new ConcreteFactory1(); f->CreateProduct();就可以得到ConcreteProduct1的對象了。

 

下面給出可執行的源代碼,運行結果的截圖放在後面。

普通工廠模式
複製代碼
 1 #include <iostream>
 2 using namespace std;
 3 
 4 //普通工廠模式
 5 
 6 //抽象產品
 7 class AbstractProduct
 8 {
 9 public:
10     virtual void getProductName() = 0;
11 };
12 
13 //具體產品1
14 class ConcreteProduct1: public AbstractProduct
15 {
16 public:
17     void getProductName()
18     {
19         cout << "ConcreteProduct1" << endl;
20     }
21 };
22 
23 //具體產品2
24 class ConcreteProduct2: public AbstractProduct
25 {
26 public:
27     void getProductName()
28     {
29         cout << "ConcreteProduct2" << endl;
30     }
31 };
32 
33 
34 //抽象工廠
35 class AbstractFactory
36 {
37 public:
38     virtual AbstractProduct* getProduct() = 0;
39 };
40 
41 //具體工廠1
42 class ConcreteFactory1: public AbstractFactory
43 {
44 public:
45     AbstractProduct* getProduct()
46     {
47         return new ConcreteProduct1();
48     }
49 };
50 
51 
52 //具體工廠2
53 class ConcreteFactory2: public AbstractFactory
54 {
55 public:
56     AbstractProduct* getProduct()
57     {
58         return new ConcreteProduct2();
59     }
60 };
61 
62 int main()
63 {
64     AbstractFactory* f1 = new ConcreteFactory1();
65     AbstractFactory* f2 = new ConcreteFactory2();
66     f1->getProduct()->getProductName();
67     f2->getProduct()->getProductName();
68     delete f1, f2;
69     return 0;
70 }
複製代碼

 

運行結果如下:

 

抽象工廠模式(Abstract Factory)

 

抽象工廠又是(普通)工廠模式的升級版,但本質是相同的。觀察UML圖,可以看到不同的地方在於多了一個抽象產品的類

ConcreateFactory1只生產ProductA1和ProductB1,即下標帶“1”的產品。可以預見,在ConcreteFactory1中的兩個方法應該如下:

 

AbstractProductA* CreateProductA()

{

         return new ProductA1();

}

AbstractProductB* CreateProductB()

{

         return new ProductB1();

}

 

ConcreateFactory2中的兩個方法類似,只是將最後的下標換成2而已。

 

下面給出可以執行的源代碼,運行截圖放在代碼的後面。

抽象工廠模式
複製代碼
  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7 // 抽象工廠模式
  8 
  9  
 10 
 11 // 抽象產品A
 12 
 13 class AbstractProductA
 14 
 15 {
 16 
 17 public:
 18 
 19          virtual void getProductName() = 0;
 20 
 21 };
 22 
 23  
 24 
 25 // 具體產品A1
 26 
 27 class ConcreteProductA1: public AbstractProductA
 28 
 29 {
 30 
 31 public:
 32 
 33          void getProductName()
 34 
 35          {
 36 
 37                    cout << "ConcreteProductA1" << endl;
 38 
 39          }
 40 
 41 };
 42 
 43  
 44 
 45  
 46 
 47 // 具體產品A2
 48 
 49 class ConcreteProductA2: public AbstractProductA
 50 
 51 {
 52 
 53 public:
 54 
 55          void getProductName()
 56 
 57          {
 58 
 59                    cout << "ConcreteProductA2" << endl;
 60 
 61          }
 62 
 63 };
 64 
 65  
 66 
 67  
 68 
 69 // 抽象產品B
 70 
 71 class AbstractProductB
 72 
 73 {
 74 
 75 public:
 76 
 77          virtual void getProductName() = 0;
 78 
 79 };
 80 
 81  
 82 
 83 // 具體產品B1
 84 
 85 class ConcreteProductB1: public AbstractProductB
 86 
 87 {
 88 
 89 public:
 90 
 91          void getProductName()
 92 
 93          {
 94 
 95                    cout << "ConcreteProductB1" << endl;
 96 
 97          }
 98 
 99 };
100 
101  
102 
103  
104 
105 // 具體產品B2
106 
107 class ConcreteProductB2: public AbstractProductB
108 
109 {
110 
111 public:
112 
113          void getProductName()
114 
115          {
116 
117                    cout << "ConcreteProductB2" << endl;
118 
119          }
120 
121 };
122 
123  
124 
125  
126 
127 // 抽象工廠
128 
129 class AbstractFactory
130 
131 {
132 
133 public:
134 
135          virtual AbstractProductA* getProductA() = 0;
136 
137          virtual AbstractProductB* getProductB() = 0;
138 
139 };
140 
141  
142 
143  
144 
145 // 具體工廠1
146 
147 class ConcreteFactory1: public AbstractFactory
148 
149 {
150 
151          AbstractProductA* getProductA()
152 
153          {
154 
155                    return new ConcreteProductA1;
156 
157          }
158 
159          AbstractProductB* getProductB()
160 
161          {
162 
163                    return new ConcreteProductB1;
164 
165          }
166 
167 };
168 
169  
170 
171 // 具體工廠2
172 
173 class ConcreteFactory2: public AbstractFactory
174 
175 {
176 
177          AbstractProductA* getProductA()
178 
179          {
180 
181                    return new ConcreteProductA2;
182 
183          }
184 
185  
186 
187          AbstractProductB* getProductB()
188 
189          {
190 
191                    return new ConcreteProductB2;
192 
193          }
194 
195 };
196 
197  
198 
199  
200 
201 int main()
202 
203 {
204 
205          AbstractFactory *f1 = new ConcreteFactory1();
206 
207          AbstractFactory *f2 = new ConcreteFactory2();
208 
209          f1->getProductA()->getProductName();
210 
211          f1->getProductB()->getProductName();
212 
213          f2->getProductA()->getProductName();
214 
215          f2->getProductB()->getProductName();
216 
217          delete f1, f2;
218 
219          return 0;
220 
221 }
複製代碼

 

運行結果如下:

 

“工廠系列”設計模式總結

下面總結一下“工廠系列”設計模式,簡單工廠模式只有一份抽象的產品,工廠是具體的;(普通)工廠模式的同樣也只有一份抽象的產品,但工廠有抽象的了;抽象工廠模式工廠當然是抽象的,但是它獨特的地方在於產品至少有兩份是抽象的。

 

建造者模式(Builder)

 

建造者模式包含一個抽象的Builder類,還有它的若干子類——ConcreteBuilder,不用理會UML圖上的Product,關鍵是看Director,Director裏面的方法Construct()其實包含了Builder指針或引用的形參,由客戶端傳入某個ConcreateBuilder對象。Construct(Builder* builder)的方法大致如下:

Construct(Builder* builder)

{

         Builder->BuildPartA();

         Builder->BuildPartB();

         …

}

由多態性可知,客戶端傳進來的ConcreteBuilder是誰,就調用誰的方法。

 

可執行的源代碼如下,運行結果在源代碼的後面。

建造者模式
複製代碼
  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5  
  6 
  7 // 建造者模式
  8 
  9  
 10 
 11 // 抽象建造者
 12 
 13 class AbstractBuilder
 14 
 15 {
 16 
 17 public:
 18 
 19          virtual void buildPart1() = 0;
 20 
 21          virtual void buildPart2() = 0;
 22 
 23 };
 24 
 25  
 26 
 27  
 28 
 29 //具體建造者1
 30 
 31 class ConcreteBuilder1: public AbstractBuilder
 32 
 33 {
 34 
 35 public:
 36 
 37          void buildPart1()
 38 
 39          {
 40 
 41                    cout << "用A構造第一部分" << endl;
 42 
 43          }
 44 
 45          void buildPart2()
 46 
 47          {
 48 
 49                    cout << "用B構造第二部分" << endl;
 50 
 51          }
 52 
 53 };
 54 
 55  
 56 
 57  
 58 
 59 //具體建造者2
 60 
 61 class ConcreteBuilder2: public AbstractBuilder
 62 
 63 {
 64 
 65 public:
 66 
 67          void buildPart1()
 68 
 69          {
 70 
 71                    cout << "用X構造第一部分" << endl;
 72 
 73          }
 74 
 75          void buildPart2()
 76 
 77          {
 78 
 79                    cout << "用Y構造第二部分" << endl;
 80 
 81          }
 82 
 83 };
 84 
 85  
 86 
 87 // 指揮者,注意其方法的參數是抽象建造者的指針
 88 
 89 class Director
 90 
 91 {
 92 
 93 public:
 94 
 95          void build(AbstractBuilder *builder)
 96 
 97          {
 98 
 99                    builder->buildPart1();
100 
101                    builder->buildPart2();
102 
103          }
104 
105 };
106 
107  
108 
109 int main()
110 
111 {
112 
113          Director d;
114 
115          d.build(new ConcreteBuilder1());
116 
117          d.build(new ConcreteBuilder2());
118 
119          return 0;
120 
121 }
複製代碼

 

運行結果如下:

 

原型模式(Prototype)

 

聽起來挺玄乎,其實說穿了,就是深拷貝問題。當一個類中包含了指針,那麼這個類一定要顯示規定三個東西:拷貝構造函數,重載”=”操作符以及析構函數。如果程序員使用編譯器默認產生的這三個函數,那麼得到的對象是原來對象的“淺拷貝”,即只是簡單拷貝了指針的值(只複製了地址),沒有複製指針指向空間的內容。“淺拷貝”只會保留最近的修改結果,而且在析構時容易出現重複析構的錯誤。

“深拷貝”是相對淺拷貝的概念說的,深拷貝不是簡單的拷貝指針的值(地址),而是重新生成了一個新的空間,這個空間裏存放的內容與傳入類內容是完全相同的。

 

請看下面“淺拷貝”的實例:

 

淺拷貝
複製代碼
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 // 原型模式,本質就是深拷貝
 8 
 9  
10 
11 // 淺拷貝,這時可以觀察到p的地址是一樣的,析構的時候因爲重複釋放同一地址空間,所以
12 
13 // 會出錯。
14 
15 class PrototypeWrong
16 
17 {
18 
19 private:
20 
21          int a;
22 
23          int *p; // 有一個指針
24 
25 public:
26 
27          PrototypeWrong()
28 
29          {
30 
31                    a = 3;
32 
33                    p = new int(2);
34 
35          }
36 
37          void outputPointerAddress()
38 
39          {
40 
41                    cout << p << endl;
42 
43          }
44 
45  
46 
47          ~PrototypeWrong()
48 
49          {
50 
51                    delete p;
52 
53          }
54 
55 };
56 
57  
58 
59 int main()
60 
61 {
62 
63          // 這一部分是錯誤的原型模式的測試樣例
64 
65          PrototypeWrong p1;
66 
67          PrototypeWrong p2 = p1;
68 
69          p1.outputPointerAddress();
70 
71          p2.outputPointerAddress();
72 
73 }
複製代碼

 

運行結果爲:

 

可以看到指針值(地址)是相同的,所以是淺拷貝,程序沒有出現“請按任意鍵繼續”的提示,說明程序其實是卡死的,原因是重複析構指針p。

 

再看看“深拷貝”的實例:

原型模式(深拷貝)
複製代碼
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 // 原型模式,本質就是深拷貝
 8 
 9  
10 
11 // 深拷貝,正確的原型模式
12 
13 class PrototypeRight
14 
15 {
16 
17 private:
18 
19          int a;
20 
21          int *p; // 有一個指針
22 
23 public:
24 
25          PrototypeRight()
26 
27          {
28 
29                    a = 3;
30 
31                    p = new int(2);
32 
33          }
34 
35  
36 
37          // 不使用默認的拷貝構造函數!
38 
39          PrototypeRight(const PrototypeRight& obj)
40 
41          {
42 
43                    a = obj.a;
44 
45                    p = new int(*obj.p);
46 
47          }
48 
49  
50 
51          void outputPointerAddress()
52 
53          {
54 
55                    cout << p << endl;
56 
57          }
58 
59  
60 
61          ~PrototypeRight()
62 
63          {
64 
65                    delete p;
66 
67          }
68 
69 };
70 
71  
72 
73 int main()
74 
75 {
76 
77          // 這一部分是正確的原型模式的測試樣例
78 
79         
80 
81          PrototypeRight p1;
82 
83          PrototypeRight p2 = p1;
84 
85          p1.outputPointerAddress();
86 
87          p2.outputPointerAddress();
88 
89          return 0;
90 
91         
92 
93 }
複製代碼

 

運行結果如下:

 

可見指針值不同了,說明指向了不同的空間,而且成功顯示了“請按任意鍵繼續”的提示符,說明析構也是正常了。但這裏的程序還不完整,按照C++的程序風格,還應該重載“=”運算符,這裏的練習便留給讀者。

 

單例模式(Singleton)

顧名思義,就是保證某個類只有一個實例(對象),這個應用還是很廣的,假設騰迅想讓用戶每次只能用一個QQ登陸,就可以用到這個模式。

 

這個UML圖非常簡單,可以說也是所有設計模式中最簡單的了,所以在面試中,常常被面試官們問起。

要使一個類只能生成一個對象,就是要限制使用它的構造函數,即將構造函數定義爲private或protected的,然後另闢一個公有方法Instance,在這個方法裏檢查instance(instance是指向本類的一個指針或引用,這在C++語法中是可以的)是否爲空指針,若爲空指針,則說明是第一次生成對象,那麼操作是允許的,instance = new Singleton(),若指針非空,說明在之前已經有一個對象(實例)了,單例模式不允許再次生成實例,因此直接返回之前生成的對象的地址。

將instance定義成static變量,就更符合“單例”模式了,因爲static變量只有一份,它屬於這個類,不屬於某個對象。相應的Instance()方法應該也定義成static的,用Singleton::Instance()來調用。注意這裏的static方法和變量是必須的,如果函數不是static,則要事先生成對象才能調用Instance,就破壞了“單例”的思想了,如果變量不是static,那麼靜態函數Instance又不能引用非static變量。

 

下面給出可以執行的源程序:

單例模式
複製代碼
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5  
 6 
 7 // 單例模式
 8 
 9 class Singleton
10 
11 {
12 
13 private:
14 
15          Singleton(){}; // 不允許直接構造其對象
16 
17          static Singleton *instance;
18 
19  
20 
21 public:
22 
23          static Singleton* createInstance()
24 
25          {
26 
27                    if(!instance)
28 
29                    {
30 
31                             // 對象第一次被創建,允許
32 
33                             cout << "創建新對象" << endl;
34 
35                             instance = new Singleton();
36 
37                    }
38 
39                    else
40 
41                    {
42 
43                             // 請求再次創建對象,不允許
44 
45                             cout << "已經創建過對象了,返回原對象" << endl;
46 
47                    }
48 
49                    return instance;
50 
51          }
52 
53          void getAddress()
54 
55          {
56 
57                    cout << "我的地址是 " << instance << endl;
58 
59          }
60 
61 };
62 
63  
64 
65 Singleton* Singleton::instance = 0; //在初始化的時候,不能在前面加static了
66 
67  
68 
69 int main()
70 
71 {
72 
73          //Singleton s;//報錯:無法訪問 private 成員(在“Singleton”類中聲明)
74 
75          Singleton *s1 = Singleton::createInstance();
76 
77          s1->getAddress();
78 
79  
80 
81          cout << endl << endl;
82 
83  
84 
85          Singleton *s2 = Singleton::createInstance();
86 
87          s2->getAddress();
88 
89          return 0;
90 
91 }
複製代碼

 

運行結果爲:


轉自 http://www.cnblogs.com/jerry19880126/archive/2012/08/08/2628321.html


其它設計模式參考:

http://blog.csdn.net/LCL_data/article/category/1373817

Facade Pattern

Decorator Pattern

Composite Pattern

Adapter Pattern

Prototype Pattern

Builder Pattern

Abstract Factory Pattern

Factory Method Pattern

Simple Factory Pattern

Bridge Pattern

Singleton Pattern

http://wenku.baidu.com/view/8fb442ce0508763231121206.html

http://wenku.baidu.com/view/fbcc28365a8102d276a22fb5.html






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章