在设计模式中,有这样的三兄弟,他们同属【创建型模式】(用于描述如何创建对象)。
刘大备:简单工厂模式(Simple Factory Pattern)
关二羽:工厂方法模式(Factory Method Pattern)
张三飞:抽象工厂模式(Abstract Factory Pattern)
它们相互关联,相互借鉴,成为人们写代码茶余饭后的谈资。
本章介绍张三飞:抽象工厂模式(Abstract Factory Pattern)的生平事迹。
上篇:
【学习设计模式4】创建型模式三结义—工厂方法模式_Aiky哇-CSDN博客不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。https://aikysay./article/details/122605747
下篇:
【学习设计模式6】单枪匹马只身一人——单例模式_Aiky哇-CSDN博客单例模式是结构最简单的设计模式之一,也是最普遍应用的设计模式之一。简单但是重要,唯一所以特别。https://aikysay./article/details/123254004
抽象工厂模式的定义
在上一节中介绍了一下工厂方法模式,又提出个问题。
你工厂方法模式中,每个工厂就能生产一种东西,那我加个产品,岂不是又要加工厂, 那岂不是越加越多,代码量狂增?
这哪能行,我们可以把长得像的产品放一堆,由一个工厂来实现嘛!所以结合了简单工厂模式和工厂方法模式,形成了新的设计模式,抽象工厂模式。
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
抽象工厂模式为创建一组对象提供了一种解决方案。
新概念:产品族和等级结构
在工厂方法模式中,因为每种工厂就生产一种产品对象,非常直观。但是到了抽象工厂模式,每种工厂要生产多个产品了,那么多产品多工厂多继承关系,怎么描述他们之间的关系呢?这时候就要新引入两个概念:产品族和产品等级结构。
产品等级结构
产品等级结构也是产品的继承结构。
如图,圆形表示的冰箱就是一个产品等级结构,三角形表示的洗衣机、方形表示的空调他们都是一个产品等级结构。
在一个产品结构中,所有的产品都属于一个父类,所有的产品都是抽象父类的具体实现。
产品族
不同的产品等级结构的一组产品组成产品族。
如图第一行实心红色表示的就是一个产品族,其中该海尔的产品族分别由海尔冰箱、海尔洗衣机和海尔空调组成。
产品族和产品等级结构的关系
我们只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。
当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。
产品族与等级结构与抽象工厂
这两个概念说到最后还是要为代码服务的。
通过了解可以知道,只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。
并且产品族和产品等级结构的定义都是抽象的,而产品本身是具体的。
所以在代码中就会变成这样:
对于一个产品等级结构,父类应该是抽象产品类,子类是具体产品类。
对于一个产品族,父类应该是工厂类,子类是具体产品类。
这么一想,根据图中所示就非常清楚了。
从产品等级结构来说,有三种产品,分别是冰箱,洗衣机,空调,这些都是抽象名称,具体的有海尔冰箱,格力空调等等。
从产品族来说,有四个工厂,海尔工厂,格力工厂,美的工厂,国美工厂。几个工厂都能生产自己的具体产品。
抽象工厂模式的流程
创建各个类型对象的抽象类,每个抽象类作为一大类、具有相同结构的具体类的父接口,称之为抽象产品类。按上面的举例来说,就是定义冰箱类,洗衣机类,空调类。创建一个抽象工厂类,作为客户端调用的接口。抽象工厂类是各个工厂类的父接口,拥有工厂类包含的接口。创建多个工厂类,具体实现抽象工厂类的接口,并且预留出创建产品接口,使每个工厂类都可以根据所传入的参数不同创建不同的具体产品对象。按上面的举例来说,就是定义海尔工厂,格力工厂,美的工厂,国美工厂。根据定义的工厂类(产品族)和产品抽象类(产品等级结构),实现所有的具体产品。就比如海尔冰箱,格力空调等等所有需要构建具体产品类的位置,都统一调用抽象工厂类,通过传入不同参数来创建。// 抽象工厂类type Ifactoty interface {createProductA() IProductAcreateProductB() IProductB}// 抽象产品类type IProductA interface {runA()}type IProductB interface {runB()}//具体工厂类type Factory1 struct {}func (f *Factory1) createProductA() IProductA {return new(ProductA1)}func (f *Factory1) createProductB() IProductB {return new(ProductB1)}type Factory2 struct {}func (f *Factory2) createProductA() IProductA {return new(ProductA2)}func (f *Factory2) createProductB() IProductB {return new(ProductB2)//具体产品类type ProductA1 struct {}func (a *ProductA1) runA() {fmt.Println("run ProductA1 A")}type ProductA2 struct {}func (a *ProductA2) runA() {fmt.Println("run ProductA2 A")}type ProductB1 struct {}func (a *ProductB1) runB() {fmt.Println("run ProductB1 B")}type ProductB2 struct {}func (a *ProductB2) runB() {fmt.Println("run ProductB2 B")}
抽象工厂模式的角色介绍
在抽象工厂模式中,角色类型和工厂方法模式是一样的。
不一样的是在工厂方法模式中,每种工厂类只需要负责创建一种产品,但是对于抽象工厂模式来说,每种工厂负责会负责多个产品。
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。
抽象工厂模式的适用场景
在以下情况下可以考虑使用抽象工厂模式:
一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
抽象工厂方法模式最燃更加具有一般性,但是还是需要设计者能够明确产品族和产品等级结构的边界。就我个人工作来说,这项工作反而更难一点。
抽象工厂模式的优缺点
主要优点
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。主要缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。最后的主要缺点,成为了抽象工厂方法模式无法解决的问题。
抽象工厂模式的设计初衷是产品等级结构的稳定。这个稳定是指不能修改。因为一旦抽象产品类增进行了修改,那么依赖于该父类的所有具体产品都需要修改,并且所有的工厂方法也需要修改,这必然是一项庞大的工作,并且会违背开闭原则。
但是相对而言,增加产品族就非常简单而且合理,不会修改之前的代码,非常完美的符合了开闭原则。
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。
正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
参考文献
工厂三兄弟之抽象工厂模式(三)_刘伟技术博客-CSDN博客
工厂三兄弟之工厂方法模式(四)_刘伟技术博客-CSDN博客
产品族和产品等级结构 - 简书