工厂模式(C++编码)

一、工厂模式概念及分类

工厂模式概念:用一个简单的类来创建实例的过程便称为工厂,用工厂方式代替外部new操作的一种设计模式称为工厂模式。这是一种创建型模式,它提供了一个创建对象的最佳方式。在工厂模式中,我们创建对象时不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象。

工厂模式分类:简单工厂模式、工厂方法模式、抽象工厂模式。

意图:定义一个常见对象的接口,让子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。

问题解决:主要解决接口选择问题。

解决方法:让其子类实现工厂接口,返回的是一个抽象的产品。

使用前提:1、编码时不能预见需要创建哪种类的实例(不同的条件下发创建不同实例);2、系统不应依赖于产品类实例如何被创建、组合和表达的细节。

关键代码:子类执行创建过程。

优点:1、使代码结构清晰,有效地封装变化,提高拓展性;2、屏蔽产品的具体实现,调用者只关心产品的接口;3、降低耦合度。

二、各类工厂模式讲解及实现

1、简单工厂模式

(1)概述

简单工厂模式时属于创建型模式,又叫做静态工厂方法模式,简单工厂模式实现由一个工厂对象决定创建出来指定产品类的实例。

(2)特点

简单工厂模式由一个工厂类根据传入的参数,动态决定应该创建哪一种产品类实例。简单工厂模式需要在工厂类中作出判断,在创建产品的时候指定响应产品创造。

(3)类图

img

(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)类图

img

(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)类图

img

(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++工厂模式分析和总结(阿里云开发者社区):https://developer.aliyun.com/article/761946

2、工厂模式——这一篇就够了(InfoQ写作平台):https://xie.infoq.cn/article/88c926822394aa1c80847dd2a

3、23种设计模式全面解析(C语言中文网):http://c.biancheng.net/design_pattern/

posted @ 2021-11-01 16:37  HOracle  阅读(4435)  评论(0编辑  收藏  举报