概述
抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。
假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。
通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构中的多个产品族中的产品对象的创建问题。如下图所示:
根据产品角色的结构图,就不难给出工厂角色的结构设计图。
可以看出,每一个工厂角色都有两个工厂方法,分别负责创建分属不同产品等级结构的产品对象。
抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口。一定要注意,这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法。比如上面例子中的主板和CPU,都是为了组装一台电脑的相关对象。不同的装机方案,代表一种具体的电脑系列。
由于抽象工厂定义的一系列对象通常是相关或相互依赖的,这些产品对象就构成了一个产品族,也就是抽象工厂定义了一个产品族。
这就带来非常大的灵活性,切换产品族的时候,只要提供不同的抽象工厂实现就可以了,也就是说现在是以一个产品族作为一个整体被切换。
核心
先上一张图:
我们还是以苦逼的程序猿为例来说抽象工厂模式的一些核心概念。通过上图你可以发现,横纵二维坐标可以确定平面上一个唯一的点,这也就是抽象工厂的核心。
产品等级结构:就是继承结构。就像上面Android,IOS,PHP这些技能继承自一个抽象的技能类(譬如前面的ICode),这个抽象类与这些子类构成了产品等级结构。 同理的Android书,C语言书,脚本书继承自一个工具书类,这个工具书抽象类与这些子类构成了等级结构。
产品族:抽象工厂模式中的产品族官方定义是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。 譬如上面的Android位于技能等级结构中,Android书位于工具书等级结构中,Android技能和Android书是位于不同产品结构的一组产品,但是任何一个程序猿都需要具备技能和工具书, 譬如一个Android程序猿需要有Android技能及Android书,所以这个Android程序猿就是一个产品族。
概念: 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
重点: 抽象工厂模式结构重要核心模块:
抽象工厂:
声明一组用于创建一族产品的方法,每一个方法对应一种产品。
具体工厂:
实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
抽象产品:
它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
具体产品:
定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
使用场景:
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。 大白话意思就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类,像上面的技能与工具书), 并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。当然了, 同样的道理就是如果各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建。
程序实例
如下实例就是上图何如上文字解释的实现代码,具体不再解释:
代码如下:
package yanbober.github.io;
/*技能等级结构部分*/
interface ICode {
void coding();
}
class CodeImplAndroid implements ICode {
@Override
public void coding() {
System.out.println("Coding Android!");
}
}
class CodeImplPHP implements ICode {
@Override
public void coding() {
System.out.println("Coding PHP!");
}
}
/*工具书等级结构*/
interface INeedBook {
void lookBook();
}
class NeedBookImplAndroid implements INeedBook {
@Override
public void lookBook() {
System.out.println("Look Android Book!");
}
}
class NeedBookImplPHP implements INeedBook {
@Override
public void lookBook() {
System.out.println("Look PHP Book!");
}
}
/*产品族*/
interface IAbstractFactory {
ICode getCodingSkill();
INeedBook getNeedBook();
}
class FactoryImplAndroid implements IAbstractFactory {
@Override
public ICode getCodingSkill() {
return new CodeImplAndroid();
}
@Override
public INeedBook getNeedBook() {
return new NeedBookImplAndroid();
}
}
class FactoryImplPHP implements IAbstractFactory {
@Override
public ICode getCodingSkill() {
return new CodeImplPHP();
}
@Override
public INeedBook getNeedBook() {
return new NeedBookImplPHP();
}
}
public class Main {
public static void main(String[] args) {
IAbstractFactory factory = new FactoryImplAndroid();
ICode code = factory.getCodingSkill();
INeedBook book = factory.getNeedBook();
code.coding();
book.lookBook();
factory = new FactoryImplPHP();
code = factory.getCodingSkill();
book = factory.getNeedBook();
code.coding();
book.lookBook();
}
}
技巧Tips:依旧可以使用配置与反射实现自动适应。
总结一把
抽象工厂模式的优点:
和前面一样,隔离具体类的生成,使客户并不需要知道什么被创建。
增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
抽象工厂模式的缺点:
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背“开闭原则”。