目录
提供一个创建一系列或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式属于创建型设计模式
四个基本要素
名称
- 抽象工厂模式(Abstract Factory Pattern)
问题
- 在软件开发中,经常需要创建一组相关或依赖的对象,例如在创建用户界面时,需要同时创建按钮、文本框、复选框等组件,而这些组件之间可能存在一定的关联关系。如果直接在客户端代码中创建这些对象,会导致客户端代码与具体产品类耦合度较高,不利于后续的维护和扩展。此外,如果需要新增或修改产品类,就需要修改客户端代码,违反了开闭原则。
方案
- 使用抽象工厂模式,定义一个抽象工厂接口或抽象类,其中包含一组用于创建产品家族的抽象方法。
- 具体的产品家族由具体的工厂子类实现,每个具体工厂负责创建特定类型的产品。
- 客户端通过调用工厂方法来创建产品,而不直接与具体产品类进行交互。
效果
- 抽象工厂模式将对象的创建与使用分离,降低了客户端代码与具体产品的耦合度,提高了系统的灵活性和可扩展性。
- 新增产品时只需添加新的具体工厂和具体产品,无需修改现有的代码。
- 符合开闭原则,客户端代码不需要修改即可支持新的产品类型。
- 可以在运行时动态切换具体工厂,实现了运行时的配置选择。
- 适用于需要创建一组相关或依赖的对象家族,并且客户端不需要知道具体对象的创建细节的场景。
模式的结构
抽象工厂(Abstract Factory)
- 定义了一个创建一组相关或依赖对象的接口。通常是一个接口或者抽象类,其中包含一组用于创建产品家族的抽象方法。
- 抽象工厂可以看作是一种工厂的工厂,它包含多个工厂方法,每个工厂方法用于创建一个特定类型的产品,具体的产品创建由具体工厂类来实现。
具体工厂(Concrete Factory)
- 实现了抽象工厂接口,负责创建特定类型的产品家族。
- 每个具体工厂负责创建一组相关的产品,具体工厂类通常通过实现抽象工厂中定义的抽象方法来创建产品。
-
实现了抽象工厂接口或抽象工厂类中定义的抽象方法,从而隐藏了对象的创建细节,提供了一种统一的接口来创建产品族。
抽象产品(Abstract Product)
- 定义了产品对象的接口或抽象类,描述了产品对象应该具有的通用行为和属性。
- 通常作为工厂模式中的一个基类,用于统一表示一组相关的产品对象。
-
抽象产品的存在使得客户端代码可以通过与抽象产品进行交互,而不需要关心具体产品的实现细节,从而实现了客户端与具体产品类的解耦。
具体产品(Concrete Product)
- 实现了抽象产品接口,属于产品族中的具体对象。
-
每个具体产品类负责实现抽象产品中定义的抽象方法,以提供具体的功能实现。
抽象工厂模式的类图
优点
- 产品族一致性: 抽象工厂模式能够确保创建的所有产品都属于同一产品族,这有助于确保这些产品之间的兼容性和一致性。
- 易于替换产品族: 由于客户端只依赖于抽象工厂和抽象产品接口,因此可以比较容易地替换整个产品族,而不需要修改客户端代码。
-
降低耦合度: 客户端代码与具体产品的实现解耦,客户端只需要与抽象工厂和抽象产品进行交互,而不需要关心具体产品的实现细节。
-
增加灵活性: 抽象工厂模式支持在运行时动态切换具体工厂,从而实现了运行时的配置选择,可以根据需要选择不同的产品族。
缺点
- 扩展性受限: 新增产品族时,除了需要添加新的具体工厂类外,还需要修改抽象工厂接口或抽象工厂类,这可能导致抽象工厂的修改,违反了开闭原则。
- 复杂性增加: 抽象工厂模式引入了多个抽象类和接口,以及多个具体工厂类,这增加了系统的复杂性和理解难度。
-
不易于单独定制产品: 由于抽象工厂模式一般是为了创建一组相关的产品对象,因此不太适合单独定制某个产品的场景,如果只需要定制某个产品,可能会显得过于笨重。
模式具体应用
在一个跨平台的软件项目中,需要创建 UI 元素,例如按钮、文本框等,同时确保所创建的元素与指定的操作系统匹配,以提供良好的用户体验。客户端代码不应该直接与具体的 UI 类耦合,而是希望能够通过统一的接口来创建 UI 元素,使得能够灵活地替换整个 UI 元素的产品族。
抽象产品 : Button.java
public abstract class Button {
public abstract void paint();
}
抽象产品 : Checkbox.java
public abstract class Checkbox {
public abstract void paint();
}
具体产品 MacButton.java
public class MacButton extends Button{
@Override
public void paint() {
System.out.println("渲染了mac系统的Button");
}
}
具体产品 MacCheckbox.java
public class MacCheckbox extends Checkbox {
@Override
public void paint() {
System.out.println("渲染了mac系统的Checkbox");
}
}
具体产品 WinButton.java
public class WinButton extends Button {
@Override
public void paint() {
System.out.println("渲染了Win系统的Button");
}
}
具体产品 WinCheckbox.java
public class WinCheckbox extends Checkbox {
@Override
public void paint() {
System.out.println("渲染了win系统的Checkbox");
}
}
抽象工厂: GuiFactory .java
public abstract class GuiFactory {
public abstract Button createButton();
public abstract Checkbox createCheckbox();
}
具体构造者(ConcreteCreator): MacFactory .java
public class MacFactory extends GuiFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
具体构造者(ConcreteCreator): WinFactory .java
public class WinFactory extends GuiFactory{
@Override
public WinButton createButton() {
return new WinButton();
}
@Override
public Checkbox createCheckbox() {
return new WinCheckbox();
}
}
应用包装:Application.java
public class Application {
private GuiFactory factory;
public Application(GuiFactory factory) {
this.factory = factory;
}
public void createUI() {
factory.createButton().paint();
factory.createCheckbox().paint();
}
}
测试:ApiTest.java
public class ApiTest {
@Test
public void abstractFactoryPattern(){
String os = "Mac";
GuiFactory factory;
if (os.equals("Windows")) {
factory = new WinFactory();
} else if (os.equals("Mac")) {
factory = new MacFactory();
} else {
throw new RuntimeException("错误!未知的操作系统。");
}
Application app = new Application(factory);
app.createUI();
}
}