持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
抽象工厂模式(Abstract Factory Pattern)
定义
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
架构图解
看着下面的架构图,有没有感觉特别熟悉,没错就是包含了工厂模式,如果把抽象工厂类换成接口就与工厂模式的架构图嵌套结构一模一样。
使用场景&解决的问题。
抽样工厂模式主要可应用于以下场景。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 在很多软件系统中需要更换界面主题或者一键换肤。
- DAO层支持多种类型的数据库,动态切换时。
- 不同操作系统代码差异化,可以切换不同操作系统时。
实现细节
我们就以Windows系统和Liunx系统的窗体和按钮风格为例,实现抽象工厂模式。
首先,定义产品规范,抽象工厂都是产品等级的,这里,分为窗体产品和按钮产品两种:
/**
* 按钮产品规范
*/
public interface Buttom {
public void buttonStyle();
}
/**
* 窗体产品规范
*/
public interface Form {
public void formStyle();
}
分别实现linux系统的窗体、按钮产品和windows系统的窗体、按钮产品,如下代码:
/**
* linux系统按钮产品
*/
public class LinuxButtom implements Buttom {
@Override
public void buttonStyle() {
System.out.println("linux系统按钮");
}
}
/**
* linux系统窗体产品
*/
public class LinuxFrom implements Form {
@Override
public void formStyle() {
System.out.println("linux系统窗体");
}
}
/**
* windows系统按钮产品
*/
public class WindowsButtom implements Buttom {
@Override
public void buttonStyle() {
System.out.println("windows系统按钮");
}
}
/**
* windows系统窗体产品
*/
public class WindowsForm implements Form {
@Override
public void formStyle() {
System.out.println("windows窗体");
}
}
接下来,需要定义工厂了,工厂需要调度按钮和窗体两个产品,这就是两个产品等级,一个工厂里包含了两个方法,这个工厂就叫产品族。我们先定义抽象工厂:
/**
* 定义抽象工厂族,调度窗体和按钮两个产品等级
*/
public abstract class AbstractFactory {
//按钮产品等级
public abstract void setButtom();
//窗体产品等级
public abstract void setForm();
}
然后我们要实现抽象工厂,抽象工厂的实现类实现两个调度方法。如下代码:
/**
* linux系统工厂实现
*/
public class LinuxAbstractFactory extends AbstractFactory {
@Override
public void setButtom() {
new LinuxButtom().buttonStyle();
}
@Override
public void setForm() {
new LinuxFrom().formStyle();
}
}
/**
* windows系统工厂实现类,实现两个产品等级
*/
public class WindowsAbstractFactory extends AbstractFactory{
@Override
public void setButtom() {
new WindowsButtom().buttonStyle();
}
@Override
public void setForm() {
new WindowsForm().formStyle();
}
}
作为设计模式的使用者,选择抽象工厂的实现类,来获得想要的产品,如下:
/**
* 使用者
*/
public class AbstractFactoryUser {
public static void main(String[] args) {
//使用者选择实现工厂类,生成产品组合
AbstractFactory factory=new WindowsAbstractFactory();
factory.setButtom();
factory.setForm();
}
}
五、抽象工厂模式在JDK中的实现
抽象工厂模式在JDK中的典型应用是JDBC的Connection接口。前面我们已经分析了JDBC注册不同数据库的驱动,用的是简单工厂模式。在注册完驱动后,会得到不同驱动的Connection对象。Connection也是jdk提供的一个接口。所以驱动注册完后,需要实现Connection接口。Connection就相当于一个抽象工厂,里面定义了Statement、PreparedStatement、CallableStatement多个产品等级。Statement、PreparedStatement、CallableStatement都是产品规范接口,所以,数据库供应商在提供驱动时,需要同时提供一套Statement,PrepareStatement的产品实现类,还要提供Connection抽象工厂的实现类。这样,在使用者那里,不管切换哪个厂商的数据库驱动,只要面向抽象工厂类开发即可,无需知道内部实现。
所以,在JDBC中,Driver利用的是简单工厂模式,其工厂类是DriverManager。Connection利用的是抽象工厂模式,它就是那个抽象工厂。
由此可以看出,工厂模式设计的初衷就是,让使用者只面对接口进行开发即可,无需关心接口的内部继承和内部实现。
优点&缺点
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码
注意事项
产品族难扩展,产品等级易扩展