抽象工厂是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。
亦称:Abstract Factory
1. 结构
- 抽象产品(Abstract Product)为构成系列产品的一组不同但相关的产品声明接口。
- 具体产品(Concrete Product)是抽象产品的多种不同类型实现。所有产品变体都必须实现相应的抽象产品。
- 抽象工厂(Abstract Factory)接口声明了一组创建各种抽象产品的方法。
具体工厂(Concrete Factory)实现抽象工厂的构建方法。每个具体工厂都对应特定产品变体,且仅创建此种产品变体。
尽管具体工厂会对具体产品进行初始化,其构建方法签名必须返回相应的抽象产品。这样,使用工厂类的客户端代码就不会与工厂创建的特定产品变体耦合。
客户端(Client)只需通过抽象接口调用工厂和产品对象,就能与任何具体工厂/ 产品变体交互。
2. 示例代码
声明产品接口以及实现 ```java /**
- 系列产品中的特定产品必须有一个基础接口。
- 所有产品变体都必须实现这个接口。
具体产品由相应的具体工厂创建。 */ public interface Cpu {
void getCpu(); }
public class Amd implements Cpu {
@Override
public void getCpu() {
System.out.println("now in AMD CPU");
}
}
public class Intel implements Cpu {
@Override
public void getCpu() {
System.out.println("now in Intel CPU");
}
}
public interface MainBoard {
void getMainBoard();
}
public class Asus implements MainBoard {
@Override
public void getMainBoard() {
System.out.println("now in ASUS main board");
}
}
public class Asus implements MainBoard {
@Override
public void getMainBoard() {
System.out.println("now in ASUS main board");
}
}
2. 声明抽象工厂以及创建实现
```java
/**
* 抽象工厂接口声明了一组能返回不同抽象产品的方法。这些产品属于同一个系列
* 且在高层主题或概念上具有相关性。同系列的产品通常能相互搭配使用。系列产
* 品可有多个变体,但不同变体的产品不能搭配使用。
*/
public interface ComputerFactory {
Cpu useCpu();
MainBoard useMainBoard();
}
/**
* 具体工厂可生成属于同一变体的系列产品。工厂会确保其创建的产品能相互搭配
* 使用。具体工厂方法签名会返回一个抽象产品,但在方法内部则会对具体产品进
* 行实例化。
* 每个具体工厂中都会包含一个相应的产品变体。
*/
public class AmdFactory implements ComputerFactory {
@Override
public Cpu useCpu() {
return new Amd();
}
@Override
public MainBoard useMainBoard() {
return new Asus();
}
}
public class IntelFactory implements ComputerFactory {
@Override
public Cpu useCpu() {
return new Intel();
}
@Override
public MainBoard useMainBoard() {
return new Msi();
}
}
创建客户端调用抽象工厂
/** * 客户端代码仅通过抽象类型(ComputerFactory、Cpu 和 MainBoard)使用工厂 * 和产品。这让你无需修改任何工厂或产品子类就能将其传递给客户端代码。 */ public class Application { private final ComputerFactory factory; public Application(ComputerFactory factory) { this.factory = factory; } public void assemble(){ factory.useCpu().getCpu(); factory.useMainBoard().getMainBoard(); } }
调用客户端传入工厂
public class RunMain { public static void main(String[] args) { // 使用AMD平台组装 ComputerFactory factory = new AmdFactory(); Application application = new Application(factory); application.assemble(); } }
3. 使用场景
如果代码需要与多个不同系列的相关产品交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于产品的具体类进行构建,在这种情况下,你可以使用抽象工厂。
抽象工厂为你提供了一个接口,可用于创建每个系列产品的对象。只要代码通过该接口创建对象,那么你就不会生成与应用程序已生成的产品类型不一致的产品。
如果你有一个基于一组抽象方法的类,且其主要功能因此变得不明确,那么在这种情况下可以考虑使用抽象工厂模式。
在设计良好的程序中,每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
4. 优缺点
优点 你可以确保同一工厂生成的产品相互匹配。
优点 你可以避免客户端和具体产品代码的耦合。
优点 单一职责原则。你可以将产品生成代码抽取到同一位置,使得代码易于维护。
优点 开闭原则。向应用程序中引入新产品变体时,你无需修改客户端代码。
缺点 由于采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂。
5. 模式之间关系
- 在许多设计工作的初期都会使用工厂方法(较为简单,而且可以更方便地通过子类进行定制),随后演化为使用抽象工厂、原型或生成器(更灵活但更加复杂)。
- 生成器重点关注如何分步生成复杂对象。抽象工厂专门用于生产一系列相关对象。抽象工厂会马上返回产品,生成器则允许你在获取产品前执行一些额外构造步骤。
- 抽象工厂模式通常基于一组工厂方法,但你也可以使用原型模式来生成这些类的方法。
- 当只需对客户端代码隐藏子系统创建对象的方式时,你可以使用抽象工厂来代替外观。
- 你可以将抽象工厂和桥接搭配使用。如果由桥接定义的抽象只能与特定实现合作,这一模式搭配就非常有用。在这种情况下,抽象工厂可以对这些关系进行封装,并且对客户端代码隐藏其复杂性。
- 抽象工厂、生成器和原型都可以用单例来实现。