1.为什么需要抽象工厂模式?
虽然工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题,但由于工厂方法模式中每个工厂只创建一类具体类的对象,如果需要的具体类很多时候,这将会导致系统当中的工厂类过多,这势必会增加系统的开销。此时,我们可以考虑将一些相关的具体类组成一个“具体类族”,由同一个工厂来统一生产,这就是我们需要抽象工厂模式的原因。
2.抽象工厂模式的定义
抽象工厂模式:
是一种为用户类提供一个创建一组相关或相互依赖的对象的接口,而且用户类无需指定他们的具体类就能得到同族的不同等级的产品的模式结构。
那什么是同族,什么是同等级的产品呢?
下图所示戴尔工厂A和 惠普工厂B所生产的键盘与鼠标对应的关系图。
通过上面这张图对刚才的定义通俗的说:在用户类中,创建了指定具体的工厂类后,在使用时就无需再关心如何对它们进行实例化的细节,也无需知道它实现了那些方法,用户类只需要跟抽象的IFactory接口打交道,调用接口的方法就能获得需要的产品,这种的工厂模式称为抽象工厂模式。
3.抽象工厂模式的结构和实现
抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。现在我们来分析其基本结构和实现方法。
①. 模式的结构
抽象工厂模式的主要角色如下:
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
下面来看一下抽象工厂模式结构的抽象uml类图
从上图 可以看出抽象工厂模式的结构同工厂方法模式的结构相似,但不同的是抽象工厂模式的每个工厂类不仅生产多种不同具体产品,而且创建产品的方法也不止一个。
②. 抽象工厂模式的应用实例
由于工厂方法模式每个工厂类只能生产一种具体产品,比如戴尔工厂类,它只能生产戴尔鼠标这一种产品类;现在我们想要戴尔工厂不仅生产戴尔鼠标,而且生产戴尔键盘,又需要惠普工厂不仅生产惠普鼠标,而且生产惠普键盘。
下面我们来看一下该例子的uml类图:
③.该例子抽象生产模式实现的代码
①创建鼠标类的共同接口
//鼠标的接口
interface mouse {
public void show();
}
②创建戴尔鼠标类实现鼠标接口,即具体的产品类
//具体的产品类(戴尔鼠标),来实现鼠标这个抽象接口
class Dellmouse implements mouse {
public void show() {
System.out.println("这是个戴尔鼠标");
}
}
③创建惠普鼠标类来实现鼠标接口,即具体的产品类
//具体的产品类(惠普鼠标),来实现鼠标这个抽象接口
class Hpmouse implements mouse {
public void show() {
System.out.println("这是个惠普鼠标");
}
}
④创建键盘类的共同接口
//键盘的接口
interface keyboard {
public void show();
}
⑤创建戴尔键盘类来实现键盘接口,即具体的产品类
//具体的产品类(戴尔键盘),来实现键盘这个抽象接口
class Dellkeyboard implements keyboard {
public void show() {
System.out.println("这是个戴尔键盘");
}
}
⑥创建惠普键盘类来实现键盘接口,即具体的产品类
//具体的产品类(惠普键盘),来实现键盘这个抽象接口
class Hpkeyboard implements keyboard {
public void show() {
System.out.println("这是个惠普键盘");
}
}
⑦创建抽象工厂类共同接口
//抽象工厂类接口
interface PCFactory {
public mouse createmouse();
public keyboard createkeyb();
}
⑧创建具体工厂类A,来实现抽象工厂类接口
//具体工厂类A,来实现抽象工厂类接口
class FactoryA implements PCFactory {
public mouse createmouse() { //实现接口的方法
return new Dellmouse(); //返回创建具体产品类1
}
public keyboard createkeyb() { //实现接口的方法
return new Dellkeyboard(); //返回创建具体产品类2
}
}
⑨创建具体工厂类B,来实现抽象工厂类接口
//具体工厂类B,来实现抽象工厂类接口
class FactoryB implements PCFactory {
public mouse createmouse() { //实现抽象接口方法
return new Hpmouse(); //返回创建具体类
}
public keyboard createkeyb() { //实现抽象接口方法
return new Hpkeyboard(); //返回创建具体类
}
}
⑩用户端的调用
//用户端的调用
public class user {
public static void main(String[] args) {
PCFactory f=new FactoryA();
f.createmouse().show(); //用户类只跟接口打交道,只需调用接口的方法
f.createkeyb().show();
PCFactory ff=new FactoryB();
ff.createmouse().show();
ff.createkeyb().show();
}
}
运行结果:
4.应用场景
抽象工厂模式通常适用于以下场景:
①当用户端需要创建的对象是一系列相互关联或相互依赖的产品族时,抽象工厂模式很适合应用这种情况。(比如说现在已经有一个工厂在生产产品,但是现在用户端想要创建另一个工厂也要生产同样的产品,这种情况抽象工厂模式就很适合)
②当系统中有多个产品族,但用户端每次只需要其中的某一族产品时,抽象工厂模式也非常适合这种情况。(比如说有的人只喜欢某一品牌的衣服和鞋子,这种情况抽象工厂模式也很适合)
③当系统中提供了产品的类库,且所有产品的接口相同时,要求客户端类不依赖产品实例的创建细节和内部结构时,抽象工厂也适合这种情况。
5.优缺点
优点
①抽象工厂模式隔离了具体产品/类的生成, 使得客户并不需要知道什么被创建。 由于这种隔离,更换或增加一个具体工厂就变得相对容易, 所有的具体工厂都实现了抽象工厂中定义的那些公共接口, 因此只需改变具体工厂的实例, 就可以在某种程度上改变整个软件系统的行为。
②当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。
③增加新的族很方便, 无须修改已有系统, 符合“开闭原则”。
缺点:
增加新的等级结构麻烦, 需要对原有系统进行较大的修改, 甚至需要修改抽象层代码,这显然会带来较大的不便, 违背了“开闭原则”。
6.总结:
抽象工厂模式是为用户端 提供一个创建一系列相关或相互依赖对象的接口,用户端无需知道他们需要的产品怎么做的,它只需要调用接口方法就行。
抽象工厂模式,不仅可以实现多个接口,而且每个工厂也可以生产多种产品类,和工厂方法模式一样,抽象工厂模式同样实现了开发封闭原则。
注意:当抽象工厂模式中的每个工厂类都只生产一种具体的产品时,这时候的抽象工厂模式相当于工厂方法模式。