文章目录
- 一、抽象工厂模式
- 1.1、产品族、产品等级
- 1.2、抽象工厂模式中的角色
- 1.3、实例
一、抽象工厂模式
在工厂方法模式中,每一个具体的工厂子类只能生成一种具体的产品,如果想要生产另外一种产品,就需要重新定义一个抽象工厂类,这样的拓展性还是会有点不足,而抽象工厂模式则是可以一个具体工厂可以生产不同的产品。
在学习抽象工厂模式之前先了解一下 产品族和产品等级 这两个概念
1.1、产品族、产品等级
- 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。
- 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的 产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。
1.2、抽象工厂模式中的角色
在抽象工厂模式结构中包含如下几个角色:
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
1.3、实例
就拿上面电视机、冰箱、空调为例:
-
抽象产品类:
- 电视机抽象产品类:
public interface Television { public void viewTV(); // 电视机的抽象方法 -> 看电视 }
- 空调产品抽象类:
public interface AirConditoner { public void changeTemperature();// 空调的抽象方法 -> 改变温度 }
-
具体产品类:
-
电视机:
- 海尔电视机类:
public class HaierTelevision implements Television { public void viewTV() { // 海尔电视机看电视的方法 } }
- TCL电视机类:
public class TCLTelevision implements Television { public void viewTV() { // TCL电视机看电视的方法 } }
- 海尔电视机类:
-
空调:
- 海尔空调类
public class HaierAirConditioner implements AirConditioner { public void changeTemperature(){ // 海尔空调改变温度的方法 } }
- TCL空调类
public class TCLAirConditioner implements AirConditioner { public void changeTemperature(){ // TCL空调改变温度的方法 } }
- 海尔空调类
-
-
抽象工厂:根据整个产品分析,这些产品都是电器类,所以创建一个电器抽象工厂,电器工厂可以创建电视机、冰箱、空调
public interface EFactory { public Television produceTelevision(); // 生产电视机的工厂方法 public AirConditioner produceAirConditioner(); // 生产空调的工厂方法 }
-
具体工厂:根据产品族分为三个不同的具体工厂
- 海尔工厂:
public class HaierFactory implements EFactory { // 生产电视机的工厂方法 public Television produceTelevision(){ return new HaierTelevision(); // 创建海尔品牌的电视机 } // 生产空调的工厂方法 public AirConditioner produceAirConditioner(){ return new HaierAirConditioner(); // 创建海尔品牌的空调 } }
- TCL工厂:
public class TCLFactory implements EFactory { // 生产电视机的工厂方法 public Television produceTelevision(){ return new TCLTelevision(); // 创建海尔品牌的电视机 } // 生产空调的工厂方法 public AirConditioner produceAirConditioner(){ return new TCLAirConditioner(); // 创建海尔品牌的空调 } }
- 海尔工厂:
-
客户端:假设我想生产海尔品牌的电视机和空调,那么代码如下:
public class Client { public static void main(String args) { // 既然是需要海尔品牌的,那就需要创建海尔品牌的工厂对象 EFactory factory = new HaierFactory(); // 然后调用工厂中的工厂方法就可以生产出想要的产品了 Television television = factory.produceTelevision(); // 生产海尔品牌的电视机 AirConditioner airConditioner = factory.produceAirConditioner();// 生产海尔品牌的空调 } }
这样就完成了一个抽象工厂模式的设计,但是在其中我们可以发现,在抽象工厂模式中,增加产品族,也就是增加一个具体子工厂很容易,也不会违背 开闭原则,但是增加新的产品等级需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。这种现象被称为 开闭原则的倾斜性。
正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
所以,抽象工厂模式的优缺点:
- 优点:
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
- 缺点:
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
使用场景:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。