工厂模式概念:用一个简单的类来创建实例的过程便称为工厂,用工厂方式代替外部new
操作的一种设计模式称为工厂模式。这是一种创建型模式,它提供了一个创建对象的最佳方式。在工厂模式中,我们创建对象时不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象。
工厂模式分类:简单工厂模式、工厂方法模式、抽象工厂模式。
意图:定义一个常见对象的接口,让子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。
问题解决:主要解决接口选择问题。
解决方法:让其子类实现工厂接口,返回的是一个抽象的产品。
使用前提:1、编码时不能预见需要创建哪种类的实例(不同的条件下发创建不同实例);2、系统不应依赖于产品类实例如何被创建、组合和表达的细节。
关键代码:子类执行创建过程。
优点:1、使代码结构清晰,有效地封装变化,提高拓展性;2、屏蔽产品的具体实现,调用者只关心产品的接口;3、降低耦合度。
二、各类工厂模式讲解及实现
1、简单工厂模式
(1)概述
简单工厂模式时属于创建型模式,又叫做静态工厂方法模式,简单工厂模式实现由一个工厂对象决定创建出来指定产品类的实例。
(2)特点
简单工厂模式由一个工厂类根据传入的参数,动态决定应该创建哪一种产品类实例。简单工厂模式需要在工厂类中作出判断,在创建产品的时候指定响应产品创造。
(3)类图
(4)例子
假设有个工厂能生产出 A、B 两种产品,当客户需要产品的时候明确告知工厂生产哪类产品,工厂需要接收顾客提供的类别信息,当新增产品的时候,工厂内部去添加新产品的生产方式。
(5)应用说明
一个工厂,多个产品,产品需要有一个虚基类,通过接收类别参数生产具体产品,利用基类指针指向此对象。
(6)编码
1 #include <iostream>
2
3 enum ProductType
4 {
5 PRODUCT_A,
6 PRODUCT_B
7 };
8
9 // 产品基类
10 class Product
11 {
12 public:
13 virtual void Show() = 0;
14 };
15
16 // 产品 A
17 class ProductA : public Product
18 {
19 public:
20 void Show()
21 {
22 std::cout << "Product A." << std::endl;
23 }
24 };
25
26 // 产品 B
27 class ProductB : public Product
28 {
29 public:
30 void Show()
31 {
32 std::cout << "Porduct B." << std::endl;
33 }
34 };
35
36 // 工厂
37 class Factory
38 {
39 public:
40 Product* Create(int type)
41 {
42 switch(type)
43 {
44 case PRODUCT_A : return new ProductA; break;
45 case PRODUCT_B : return new ProductB; break;
46
47 default : break;
48 }
49 }
50 };
51
52 int main()
53 {
54 Factory *factory = new Factory();
55
56 factory->Create(PRODUCT_A)->Show();
57 factory->Create(PRODUCT_B)->Show();
58
59 return 0;
60 }
(7)缺点
工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了,违背开闭原则。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。
2、工厂方法模式
(1)概述
多个工厂,多个产品,每个产品对应一个工厂,此时工厂和产品都通过虚基类方式构建。
(2)特点
定义一个用于创建对象的接口,让子类决定实例化哪一个类。当增加一个新产品时,同时增加一个新工厂。增加新工厂属于扩展,不会修改以前工厂类和产品类的任何代码。可以看过多个独立的简单工厂模式构成了工厂方法模式。工厂方法让类的实例化推迟到子类中进行。
(3)类图
(4)例子
假设现在有 A、B 两种产品,则开两个工厂,工厂 A 负责生产产品 A,工厂 B 负责生产产品 B,客户只知道创建产品的工厂名,而不知道具体的产品名,工厂不需要再接收客户的产品类别,而只去生产产品。
(5)应用说明
把简单工厂模式中的工厂类抽象出一个结构,这个接口只有一个创建抽象产品的工厂方法,工厂方法模式解决了简单工厂模式中出现的缺点。
(6)编码
1 #include <iostream>
2
3 // 产品基类
4 class Product
5 {
6 public:
7 virtual void Show() = 0;
8 };
9
10 // 工厂基类
11 class Factory
12 {
13 public:
14 virtual Product* Create() = 0;
15 };
16
17 // 产品 A
18 class ProductA : public Product
19 {
20 public:
21 void Show()
22 {
23 std::cout << "Product A." << std::endl;
24 }
25 };
26
27 // 产品 B
28 class ProductB : public Product
29 {
30 public:
31 void Show()
32 {
33 std::cout << "Porduct B." << std::endl;
34 }
35 };
36
37 // 工厂 A
38 class FactoryA : public Factory
39 {
40 public:
41 Product* Create()
42 {
43 return new ProductA;
44 }
45 };
46
47 // 工厂 B
48 class FactoryB : public Factory
49 {
50 public:
51 Product* Create()
52 {
53 return new ProductB;
54 }
55 };
56
57 int main()
58 {
59 FactoryA *factoryA = new FactoryA();
60 FactoryB *factoryB = new FactoryB();
61
62 factoryA->Create()->Show();
63 factoryB->Create()->Show();
64
65 return 0;
66 }
(7)适用场景
工厂方法模式和简单工厂模式虽然都是通过工厂来创建对象,他们之间最大的不同是——工厂方法模式在设计上完全完全符合开闭原则。适用场景:1、一个类不知道它所需要的对象的类(在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类);2、一个类通过其子类来指定创建哪个对象(在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展);3、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
(8)具体应用
-
日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
-
数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
-
设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
(9)缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
3、抽象工厂模式
(1)概述
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。
(2)特点
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
(3)类图
(4)例子
假如 A 产品中有 A1 和 A2 两种型号的产品,B 产品中有 B1 和 B2 两种型号的产品,这个时候使用抽象工厂模式,还是开设两家工厂,工厂等级为 1 则负责生产 A1 、B1 型号产品,工厂等级为 2 则负责生产 A2、B2 型号的产品。这样减少了工厂类和产品类在项目中的数量,并完成针对多个产品等级结构的抽象。
(5)编码
1 #include <iostream>
2
3 // Product A
4 class ProductA
5 {
6 public:
7 virtual void Show() = 0;
8 };
9
10 class ProductA1 : public ProductA
11 {
12 public:
13 void Show()
14 {
15 std::cout << "Product A1." << std::endl ;
16 }
17 };
18
19 class ProductA2 : public ProductA
20 {
21 public:
22 void Show()
23 {
24 std::cout << "Product A2." << std::endl ;
25 }
26 };
27
28 // Product B
29 class ProductB
30 {
31 public:
32 virtual void Show() = 0;
33 };
34
35 class ProductB1 : public ProductB
36 {
37 public:
38 void Show()
39 {
40 std::cout << "Product B1." << std::endl ;
41 }
42 };
43
44 class ProductB2 : public ProductB
45 {
46 public:
47 void Show()
48 {
49 std::cout << "Product B2." << std::endl ;
50 }
51 };
52
53 // Factory
54 class Factory
55 {
56 public:
57 virtual ProductA* CreateProductA() = 0;
58 virtual ProductB* CreateProductB() = 0;
59 };
60
61 class Factory1 : public Factory
62 {
63 public:
64 ProductA* CreateProductA()
65 {
66 return new ProductA1();
67 }
68
69 ProductB* CreateProductB()
70 {
71 return new ProductB1();
72 }
73 };
74
75 class Factory2 : public Factory
76 {
77 ProductA* CreateProductA()
78 {
79 return new ProductA2();
80 }
81
82 ProductB* CreateProductB()
83 {
84 return new ProductB2();
85 }
86 };
87
88 int main()
89 {
90 Factory *factoryObj1 = new Factory1();
91 ProductA *productObjA1 = factoryObj1->CreateProductA();
92 ProductB *productObjB1 = factoryObj1->CreateProductB();
93
94 productObjA1->Show();
95 productObjB1->Show();
96
97 Factory *factoryObj2 = new Factory2();
98 ProductA *productObjA2 = factoryObj2->CreateProductA();
99 ProductB *productObjB2 = factoryObj2->CreateProductB();
100
101 productObjA2->Show();
102 productObjB2->Show();
103
104 return 0;
105 }
(6)适用场景
-
一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
-
系统中有多于一个的产品族,而每次只使用其中某一产品族。
-
属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
-
系统结构稳定,不会频繁的增加对象。
(7)开闭原则的倾斜性
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为开闭原则的倾斜性。开闭原则要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:1、增加产品族——对于增加新的产品族,工厂方法模式很好的支持了开闭原则,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。2、增加新的产品等级结构——对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则。
正因为抽象工厂模式存在开闭原则的倾斜性,它以一种倾斜的方式来满足开闭原则,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
(8)优点
易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这样就使得改变一个应用的具体工厂变得非常容易,只需要改变具体工厂即可使用不同的产品配置。让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂实现分离,不会出现在客户代码中。
(9)缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
三、工厂模式的退化过程
四、Reference
1、C++工厂模式分析和总结(阿里云开发者社区):
2、工厂模式——这一篇就够了(InfoQ写作平台):
3、23种设计模式全面解析(C语言中文网):
原文链接: https://www.cnblogs.com/horacle/p/15494358.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/214634
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!