抽象工厂模式定义
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式
- 提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
- 抽象工厂允许客户端使用抽象的接口来创建一组相关的产品,而具体的创建工作由具体工厂类完成。
基本概念
- 抽象工厂(Abstract Factory):声明了一组用于创建抽象产品的方法,每个方法对应一个产品。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品对象。
- 抽象产品(Abstract Product):为一类产品声明接口。
- 具体产品(Concrete Product):实现了抽象产品接口,由具体工厂创建,形成产品族。
抽象工厂模式的种类
抽象工厂模式的实现方式主要有两种:
- 普通实现:直接使用接口或抽象类定义抽象工厂和抽象产品,具体工厂和具体产品实现这些接口。
- 反射机制实现:利用反射和配置文件,使得客户端可以动态地选择具体工厂,实现更高的灵活性。
使用场景
- 需要创建一系列相关或相互依赖的对象,且需要避免指定它们的具体类。
- 系统的产品具有多种系列,且系统只消费其中某一系列的产品。
- 产品族概念:在抽象工厂模式中,产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。
示例:UI 组件的跨平台实现
假设我们正在开发一个跨平台的 GUI 应用程序,需要在不同的操作系统(如 Windows、Mac)上显示不同风格的按钮和文本框。使用抽象工厂模式可以很好地解决这个问题。
1. 定义抽象产品
// 抽象产品:按钮
public interface Button {
void click();
}
// 抽象产品:文本框
public interface TextField {
void setText(String text);
String getText();
}
2. 定义具体产品
// Windows 风格的按钮
public class WindowsButton implements Button {
@Override
public void click() {
System.out.println("Windows 风格的按钮被点击。");
}
}
// Windows 风格的文本框
public class WindowsTextField implements TextField {
private String text;
@Override
public void setText(String text) {
this.text = text;
System.out.println("Windows 风格的文本框设置文本:" + text);
}
@Override
public String getText() {
return text;
}
}
// Mac 风格的按钮
public class MacButton implements Button {
@Override
public void click() {
System.out.println("Mac 风格的按钮被点击。");
}
}
// Mac 风格的文本框
public class MacTextField implements TextField {
private String text;
@Override
public void setText(String text) {
this.text = text;
System.out.println("Mac 风格的文本框设置文本:" + text);
}
@Override
public String getText() {
return text;
}
}
3. 定义抽象工厂
// 抽象工厂
public interface GUIFactory {
Button createButton();
TextField createTextField();
}
4. 定义具体工厂
// Windows 工厂
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
// Mac 工厂
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
5. 客户端代码
public class Client {
public static void main(String[] args) {
GUIFactory factory;
Button button;
TextField textField;
// 根据操作系统选择具体工厂
String osType = "Windows"; // 这可以从配置文件或系统参数获取
if (osType.equalsIgnoreCase("Windows")) {
factory = new WindowsFactory();
} else if (osType.equalsIgnoreCase("Mac")) {
factory = new MacFactory();
} else {
throw new IllegalArgumentException("未知的操作系统类型");
}
// 通过工厂创建产品
button = factory.createButton();
textField = factory.createTextField();
// 使用产品
button.click();
textField.setText("Hello, World!");
}
}
输出结果(在 Windows 平台):
Windows 风格的按钮被点击。
Windows 风格的文本框设置文本:Hello, World!
6. 新增产品族或产品等级结构
如果需要支持新的操作系统(如 Linux),只需添加对应的具体工厂和具体产品类,而不需要修改现有代码。
抽象工厂模式的优势
- 分离接口和实现:客户端使用抽象工厂来创建产品,避免了对具体产品类的依赖。
- 产品族一致性:确保同一工厂创建的产品属于同一产品族,避免了产品间的不兼容问题。
- 符合开闭原则:增加新的产品族时,只需添加新的具体工厂和产品类,无需修改现有代码。
抽象工厂模式的意义
- 提高系统的可扩展性:通过引入新的工厂和产品,系统可以支持新的产品族,满足不断变化的需求。
- 降低系统的耦合度:客户端通过抽象接口与工厂和产品交互,具体实现细节对客户端透明。
- 便于产品族的切换:只需更改具体工厂,客户端即可使用不同的产品族,实现灵活的系统配置。
抽象工厂模式与工厂方法模式的区别
虽然抽象工厂模式和工厂方法模式都属于创建型设计模式,都涉及到工厂和产品的概念,但它们在目的、结构和使用场景上有明显的区别。
1. 目的不同
工厂方法模式:关注创建单一产品,定义一个创建对象的接口,让子类决定实例化哪一个类。其目的是将对象的创建与使用解耦。
抽象工厂模式:关注创建一系列相关的产品,提供一个接口,用于创建相关或依赖的对象的家族,而无需明确指定具体类。其目的是为一组相关或相互依赖的对象提供一个一致的创建方式。
2. 结构不同
-
工厂方法模式:
- 角色:抽象产品、具体产品、抽象工厂、具体工厂。
- 特点:每个具体工厂只生产一种具体产品。
-
抽象工厂模式:
- 角色:抽象工厂、具体工厂、抽象产品族、具体产品族。
- 特点:每个具体工厂生产多个具体产品,产品组成一个产品族。
3. 使用场景不同
工厂方法模式:适用于创建单个产品,客户端不需要知道具体产品的类名,只需要知道工厂接口。
抽象工厂模式:适用于创建一组相关的产品,客户端需要使用这些产品,但是不需要知道具体的产品类名,只需要知道产品的接口和工厂。
4. 扩展性不同
工厂方法模式:增加新的产品,需要新增具体产品类和对应的具体工厂类。
-
抽象工厂模式:
- 增加产品等级结构(新产品类型):需要修改抽象工厂,增加新的产品创建方法,以及所有的具体工厂类,违背了开闭原则。
- 增加产品族(新产品系列):只需新增具体工厂类和具体产品类,符合开闭原则。
5. 示例区别
工厂方法模式:比如,在日志系统中,通过工厂方法模式创建不同类型的日志记录器(文件日志、数据库日志),每个工厂只创建一种日志记录器。
抽象工厂模式:在跨平台的 GUI 应用中,通过抽象工厂模式创建一组相关的 UI 组件(按钮、文本框),每个工厂创建一组风格一致的组件(如 Windows 风格、Mac 风格)。
结语
抽象工厂模式提供了一种解决方案,使得客户端可以使用抽象的接口来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。这在需要创建产品族的场景中非常有用,可以确保产品族的一致性。
通过区分抽象工厂模式和工厂方法模式,我们可以更好地理解设计模式的应用场景和适用条件,选择最适合的模式来解决实际问题。
启发
抽象工厂模式通过对产品族的封装,实现了对变化的隔离,体现了面向对象设计的开闭原则和依赖倒置原则。这启示我们,在软件设计中,应当尽可能地面向抽象编程,减少对具体实现的依赖。
抽象 是一个架构师最重要的能力亦或者是最基础的