意图
抽象工厂模式(Abstract Factory)是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。
解决方案
首先,抽象工厂模式建议为系列中的每件产品明确声明接口。然后,确保所有产品变体都继承这些接口。
接下来,我们需要声明抽象工厂——包含系列中所有产品构造方法的接口。这些方法必须返回抽象产品类型,即我们之前抽取的那些接口。
对于系列产品的每个变体,我们都将基于 抽象工厂
接口创建不同的工厂类。每个工厂类都只能返回特定类别的产品。
客户端代码可以通过相应的抽象接口调用工厂和产品类。你无需修改实际客户端代码,就能更改传递给客户端的工厂类,也能更改客户端代码接收的产品变体。
抽象工厂模式结构
抽象产品 (Abstract Product) 为构成系列产品的一组不同但相关的产品声明接口。
具体产品 (Concrete Product) 是抽象产品的多种不同类型实现。所有变体都必须实现相应的抽象产品。
抽象工厂 (Abstract Factory) 接口声明了一组创建各种抽象产品的方法。
具体工厂 (Concrete Factory) 实现抽象工厂的构建方法。每个具体工厂都对应特定产品变体,且仅创建此种产品变体。
尽管具体工厂会对具体产品进行初始化,其构建方法签名必须返回相应的抽象产品。这样,使用工厂类的客户端代码就不会与工厂创建的特定产品变体耦合。客户端 (Client)只需通过抽象接口调用工厂和产品对象,就能与任何具体工厂/产品变体交互。
抽象工厂模式适合应用场景
- 如果代码需要与多个不同系列的相关产品交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建,在这种情况下,你可以使用抽象工厂。
抽象工厂为你提供了一个接口,可用于创建每个系列产品的对象。只要代码通过该接口创建对象,那么你就不会生成与应用程序已生成的产品类型不一致的产品。
- 如果你有一个基于一组工厂方法的类,且其主要功能因此变得不明确,那么在这种情况下可以考虑使用抽象工厂模式。
在设计良好的程序中,每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
抽象工厂模式优缺点
优点:
- 你可以确保同一工厂生成的产品相互匹配。
- 你可以避免客户端和具体产品代码的耦合。
- 单一职责原则。你可以将产品生成代码抽取到同一位置,使得代码易于维护。
- 开闭原则。向应用程序中引入新产品变体时,你无需修改客户端代码。
缺点:
由于采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂。
与其他模式的关系
-
在许多设计工作的初期都会使用工厂方法模式 (较为简单,而且可以更方便地通过子类进行定制),随后演化为使用抽象工厂模式、原型模式或生成器模式 (更灵活但更加复杂)。
-
生成器重点关注如何分步生成复杂对象。抽象工厂专门用于生产一系列相关对象。抽象工厂会马上返回产品,生成器则允许你在获取产品前执行一些额外构造步骤。
-
你可以将抽象工厂和桥接模式搭配使用。如果由桥接定义的抽象只能与特定实现合作,这一模式搭配就非常有用。在这种情况下,抽象工厂可以对这些关系进行封装,并且对客户端代码隐藏其复杂性。
在 Java 中使用模式
使用示例:抽象工厂模式在 Java 代码中很常见。许多框架和程序库会将它作为扩展和自定义其标准组件的一种方式。
以下是来自核心 Java 程序库的一些示例:
示例代码
抽象产品 (Abstract Product)
public interface Button {
void render();
}
public interface Checkbox {
void render();
}
具体产品 (Concrete Product)
public class LinuxButton implements Button {
@Override
public void render() {
System.out.println("Render Button in Linux system");
}
}
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("Render Button in Windows system");
}
}
public class LinuxCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("Render Checkbox in Linux system");
}
}
public class WindowsCheckbox implements Checkbox {
@Override
public void render() {
System.out.println("Render Checkbox in Windows system");
}
}
抽象工厂 (Abstract Factory)
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
具体工厂 (Concrete Factory)
public class LinuxFactory implements GUIFactory {
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public Checkbox createCheckbox() {
return new LinuxCheckbox();
}
}
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
客户端 (Client)
public class Client {
public static void main(String[] args) {
GUIFactory factory;
if (System.getProperty("os.name").contains("Windows")) {
factory = new WindowsFactory();
} else {
factory = new LinuxFactory();
}
Button button = factory.createButton();
Checkbox checkbox = factory.createCheckbox();
button.render();
checkbox.render();
}
}