设计模式(三)抽象工厂模式
最后更新于:2022-04-01 11:05:08
### 一、模式定义
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又
称为Kit模式,属于对象创建型模式。
### 二、产品族和等级结构
为了更清晰地理解抽象工厂模式,需要先引入两个概念:
**产品等级结构 :**产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电
视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
**产品族 :**在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视
机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_571758527750b.jpg "")
从上边的图中我们可以更清晰的看到同族产品和同一等级结构的产品的联系和区别。海尔电视机和长虹电视机都是电视机的子类,这样的关
系叫做同一等级结构;海尔电视机和海尔电冰箱都是海尔公司生产的产品,所以他们都是同族产品。
我们还可以通过下边的相图可以更加清楚的看出来,横轴表示等级结构,向横轴做垂线,在同一条垂线上的是同一个等级结构,纵轴便是产
品组,向纵轴做垂线,同一条垂线上的是一个产品族。
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_57175852b3882.jpg "")
如果看了上边的两种解释你还是不能明白同族产品和同一等级结构的产品的话,那么可以看一下下面的这个非常暴力的例子。
你的爷爷和你的外公,你的爸爸和你舅舅,你和你的表弟都是同一等级结构,而你的爷爷和你的爸爸还有你是一个产品族,你的外公和你的
舅舅还有你的表弟是一个产品族,现在能明白什么是产品族什么是同一等级结构了吧。
### 三、模式动机
- 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工
厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
- 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用
抽象工厂模式。
- 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式
针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对
象的创建
。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效
率。
### 四、模式结构
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_57175852c96eb.jpg "")
从上图看以看出抽象工厂模式和工厂方法模式类似都是由四部分组成。
- 抽象工厂(AbstractFactory)角色:担任这个角色的是抽象工厂模式的核心,是与应用系统的商业逻辑无关的。通常使用Java接口或者
抽象Java类实现。所有的具体工厂必须实现这个Java接口或继承这个抽象的Java类。
- 具体工厂(Factory)角色:这个角色直接在客户端的调用下创建产品的实例,这个角色含有选择合适的产品对象的逻辑,而这个逻辑是
与应用系统商业逻辑紧密相关的。
- 抽象产品(AbstractProduct)角色:担任这个角色的类是抽象工厂模式所创建的对象的父类,或它们共同拥有的接口。通常使用Java接
口或者抽象Java类实现这一角色。
- 具体产品(Product)角色:抽象工厂模式所创建的任何产品对象都是一个具体的产品类的实例。这是客户端最终需要的东西,其内部一
定充满了应用系统的商业逻辑。通常使用具体Java类实现这个角色。
与工厂方法模式不同的是,抽象工厂模式中的具体工厂不再是只能创建一种产品,一个具体的工厂可以创建一个产品族的产品。
### 五、实例分析
我们接着前边土豪的故事继续讲。话说这个土豪还有一个爱好,就是打猎。但是土豪打猎是有要求的(毕竟土豪嘛,要就就得高一点),他
如果坐Audi车去打猎,那么他就一定要使用AK47这把枪(这是去打猎吗?【偷笑】);如果他坐Benz车去打猎那么他就一定要用M4A1这把枪
,如果按照我们前边讲的工厂方法模式来编程,那么应该是建立一个Car的抽象工厂类CarFactory,然后Benz车的工厂继承自这个抽象的父类
并实现生产Benz车的方法,Audi车的工厂继承自这个抽象的父类并实现生产Audi车的方法。并且还要有一个生产Gun的抽象工厂类,由它的具
体子类工厂来实现生产AK47和M4A1。
这样做是非常麻烦的,我们已经知道了如果土豪做Audi的话那他一定是使用AK47,所以我们可以使用一个工厂来同时生产Audi车和AK47,注
意我说的前提是我们已经知道了土豪一定是Audi车和AK47一起使用的,如果不满足这个条件的话是不能使用抽象工厂模式来解决这个问题的
。
具体的代码如下:
~~~
package com.myfactory.abstractfactory;
/**
* 仅仅定义生产同一族产品的两个不同等级结构的产品接口,具体的实现由子类工厂来实现
* @author xing
*
*/
public abstract class AbstractFactory {
public abstract Car getCar();
public abstract Gun getGun();
}
~~~
~~~
package com.myfactory.abstractfactory;
/**
* Audi车的工厂同时生产Audi车和配套的AK47
* @author xing
*
*/
public class AudiFactory extends AbstractFactory{
public Car getCar() {
return new Audi();
}
public Gun getGun() {
return new AK47();
}
}
~~~
汽车的类和前边的例子是一样的这里不再重复,最后会附上完整的代码。
~~~
package com.myfactory.abstractfactory;
public abstract class Gun {
abstract void fire();
}
~~~
~~~
package com.myfactory.abstractfactory;
public class AK47 extends Gun{
public AK47(){
System.out.println("Create an AK47");
}
public void fire(){
System.out.println("AK47 start fire");
}
}
~~~
在Main函数中就可以通过一个工厂创建两个对象。
~~~
package com.myfactory.abstractfactory;
public class Main {
public static void main(String[] args) throws Exception {
//奔驰车司机
AbstractFactory factory = new BenzFactory();
//今天想做奥迪车
Car car = factory.getCar();
//开车
car.drive();
//获得开Benz时要用的枪
Gun gun = factory.getGun();
//开火
gun.fire();
}
}
~~~
### 六、模式优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体
工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用
抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决
定其行为的软件系统来说,是一种非常实用的设计模式。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
### 七、模式缺点
- 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持
新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。
### 八、适用场景
1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2、这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
3、同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4、系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖与实现。
### 九、抽象工厂模式的退化
当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂
方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退
化成简单工厂模式。
源码下载:[http://download.csdn.net/detail/xingjiarong/9296125](http://download.csdn.net/detail/xingjiarong/9296125)