声明:本博客参考C语言中文网:C语言中文网连接
主要记录学习以下内容:
一、简单工厂模式
二、工厂方法模式
三、抽象工厂模式
每个大要点都主要包括以下两部分内容:
(1)基本概念和模型结构(包括一些名词解释、模型结构分析(C语言中文网截取))
(2)示例代码(包括代码,和代码的模型分析,模型优缺点分析)
工厂模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作放到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。
一、简单工厂模式
1.基本概念和模型结构
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。
简单来说,简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。
简单工厂模式每增加一个产品就要增加一个具体产品类,对原本的具体工厂类进行修改扩充,这增加了系统的复杂度,违背了“开闭原则”。在下面代码示例中可以看出来
模型结构:
抽象产品:是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
具体产品:是简单工厂模式的创建目标。
简单工厂:是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
2.代码示例和模型
//简单工厂模式enum TeaKind {tgy = 0, lj, dhp };class DrinkBase //具体产品的抽象父类{public:virtual ~DrinkBase() {}virtual void make() = 0;};class tgyTea :public DrinkBase //具体产品1{public:void make(){cout << "制作了一份铁观音茶叶!" << endl;}};class ljTea :public DrinkBase//具体产品2{public:void make(){cout << "制作了一份龙井茶叶!" << endl;}};class dhpTea :public DrinkBase//具体产品3{public:void make(){cout << "制作了一份大红袍茶叶!" << endl;}};class SimpleFactory //工厂类{public:DrinkBase* MakeTea(TeaKind kind)//创建{switch (kind){case(lj):return new ljTea();break;case(dhp):return new dhpTea();break;case(tgy):return new tgyTea();break;default:break;}return nullptr;}};int main(){//可以将MakeTea方法设置为静态方法,用类名访问,不需要创建工厂对象。这里用的是创建工厂对象SimpleFactory factory;//创建工厂DrinkBase* li_ptr = factory.MakeTea(lj);//用工厂制作龙井茶叶li_ptr->make();DrinkBase* dhp_ptr = factory.MakeTea(dhp);//用工厂制作大红袍茶叶dhp_ptr->make();DrinkBase* tgy_ptr = factory.MakeTea(tgy);//用工厂制作铁观音茶叶tgy_ptr->make();delete li_ptr;delete dhp_ptr;delete tgy_ptr;return 0;}
(C语言中文网中是讲解设计模式示例是用的java,将类和方法都设置为静态,那么就无法用类实例化对象,但是我尝试了一下,发现静态类在C++好像不起什么作用,就是C++中类加不加静态与类的原本使用没什么差别)
运行结果:
模型:
其实可以发现简单工厂模式有很多的问题,最严重的就是违反了开闭原则,除此之外还能挑出来其他问题,看一下C语言中文网中对简单工厂模式的评价:
优点和缺点
优点:
(1)工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
(2)客户端无需知道所创建具体产品的类名,只需知道参数即可。
缺点:
(1)简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
(2)使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
(3)系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
(4)简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
应用场景
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
二、工厂方法模式
1.基本概念和模型结构
模式的结构:
工厂方法模式的主要角色如下。
抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
模型结构:
2.代码示例和模型
class DrinkBase //抽象产品类{public:virtual ~DrinkBase() {}virtual void make() = 0;};class tgyTea :public DrinkBase //具体产品1{public:void make(){cout << "制作了一份铁观音茶叶!" << endl;}};class ljTea :public DrinkBase//具体产品2{public:void make(){cout << "制作了一份龙井茶叶!" << endl;}};class dhpTea :public DrinkBase//具体产品3{public:void make(){cout << "制作了一份大红袍茶叶!" << endl;}};class FactoryBase //抽象工厂类{public:virtual DrinkBase* TeaMake() = 0;};class Factory_lj :public FactoryBase //具体工厂1{public:DrinkBase* TeaMake(){return new ljTea();}};class Factory_tgy :public FactoryBase //具体工厂2{public:DrinkBase* TeaMake(){return new tgyTea();}};class Factory_dhp :public FactoryBase //具体工厂3{public:DrinkBase* TeaMake(){return new dhpTea;}};int main(){Factory_dhp dhpFac;Factory_lj ljFac;Factory_tgy tgyFac;DrinkBase* dhpFac_ptr = dhpFac.TeaMake();dhpFac_ptr->make();//制作大红袍DrinkBase* ljFac_ptr = ljFac.TeaMake();ljFac_ptr->make();//制作龙井DrinkBase* tgyFac_ptr = tgyFac.TeaMake();tgyFac_ptr->make();//制作铁观音delete dhpFac_ptr;delete ljFac_ptr;delete tgyFac_ptr;return 0;}
运行结果:
对应的模型:
可以看出来,工厂方法模式与简单工厂模式最大的区别就是:简单工厂模式把一类产品都放到一个工厂中生产,而工厂方法模式是每个产品都有一个对应的工厂生产,所以工厂方法模式的工厂类比较多,但是有一个非常大的好处就是,弥补了简单工厂模式的致命伤——遵循了开闭原则。如果工厂方法模式需要添加产品,那么就添加具体的产品类和生产这个具体产品的具体工厂就好了,缺点就是类太多了,封装程度太低。低耦合高内聚中的低耦合做到了,但是高内聚并没有体现出来。
看一C语言中文网对简单工厂模式的评价
优点:
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
类的个数容易过多,增加复杂度
增加了系统的抽象性和理解难度
抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
客户不关心创建产品的细节,只关心产品的品牌
三、抽象工厂模式
1.基本概念和模型结构
抽象工厂模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
使用抽象工厂模式一般要满足以下条件:
系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
系统一次只可能消费其中某一族产品,即同族的产品一起使用。
模式的结构
抽象工厂模式的主要角色如下。
**抽象产品:**定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
**具体产品:**实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
**抽象工厂:**提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
**具体工厂:**主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
2.代码示例和模型
代码:
class AbstractRGT //抽象产品类,冰箱{public:virtual ~AbstractRGT() {}virtual void make_rgt() = 0;};class HaierRGT :public AbstractRGT {public:void make_rgt(){cout << "制作出来一个海尔冰箱!" << endl;}};class MeidiRGT :public AbstractRGT {public:void make_rgt(){cout << "制作出来一个美的冰箱!" << endl;}};class GeliRGT :public AbstractRGT{public:void make_rgt(){cout << "制作出来一个格力冰箱!" << endl;}};class AbstractAIRCDT //抽象产品类,空调{public:virtual ~AbstractAIRCDT() {}virtual void make_aircdt() = 0;};class MeidiAIRCDT :public AbstractAIRCDT {public:void make_aircdt(){cout << "制作出来一个美的空调!" << endl;}};class HaierAIRCDT :public AbstractAIRCDT{public:void make_aircdt(){cout << "制作出来一个海尔空调!" << endl;}};class GeliAIRCDT :public AbstractAIRCDT{public:void make_aircdt(){cout << "制作出来一个格力空调!" << endl;}};class AbstractFactory //抽象工厂类,在这里以品牌为一个商品族{public:virtual ~AbstractFactory() {}virtual AbstractAIRCDT* Aircdt_make() = 0;virtual AbstractRGT* Rgt_make() = 0;};class HaierFactory:public AbstractFactory//海尔族的商品{public:AbstractAIRCDT* Aircdt_make(){return new HaierAIRCDT();}AbstractRGT* Rgt_make(){return new HaierRGT();}};class MeidiFactory :public AbstractFactory//美的族的上坪{public:AbstractAIRCDT* Aircdt_make(){return new MeidiAIRCDT();}AbstractRGT* Rgt_make(){return new MeidiRGT();}};class GeliFactory :public AbstractFactory//格力族的商品{public:AbstractAIRCDT* Aircdt_make(){return new GeliAIRCDT();}AbstractRGT* Rgt_make(){return new GeliRGT();}};int main(){MeidiFactory meidi_fac;AbstractAIRCDT* meidiair_ptr = meidi_fac.Aircdt_make();meidiair_ptr->make_aircdt();AbstractRGT* meidirgt_ptr = meidi_fac.Rgt_make();meidirgt_ptr->make_rgt();HaierFactory haier_fac;AbstractAIRCDT* haierair_ptr = haier_fac.Aircdt_make();haierair_ptr->make_aircdt();AbstractRGT* haierrgt_ptr = haier_fac.Rgt_make();haierrgt_ptr->make_rgt();GeliFactory geli_fac;AbstractAIRCDT* geliair_ptr = geli_fac.Aircdt_make();geliair_ptr->make_aircdt();AbstractRGT* gelirgt_ptr = geli_fac.Rgt_make();gelirgt_ptr->make_rgt();return 0;}
运行结果:
模型:
优点:
可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。
模式的结构与实现
抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。现在我们来分析其基本结构和实现方法。
适用场景:
(1)当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
(2)系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
(3)系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
模式的扩展:
抽象工厂模式的扩展有一定的“开闭原则“倾斜性”:
当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。