抽象工厂模式
引言
在软件开发中,我们常常需要处理多个系列的产品对象。当这些产品对象之间存在一定的约束或依赖关系时,传统的工厂模式可能无法很好地满足需求。抽象工厂模式(Abstract Factory Pattern)就是在这样的背景下诞生的,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
诞生背景
抽象工厂模式最早由Erich Gamma等人在《设计模式:可复用面向对象软件的基础》一书中提出。它是设计模式中最为复杂的模式之一,适用于需要创建多个产品族的场景。随着软件系统的复杂度增加,开发者需要一种方法来确保来自同一产品族的对象能够正确地协同工作,抽象工厂模式正是为了解决这个问题而设计的。
演进过程
抽象工厂模式最初是作为GoF(Gang of Four)设计模式的一部分提出的。随着时间的推移,这个模式被广泛应用于各种编程语言和框架中。随着面向对象编程的发展,抽象工厂模式也经历了不同的变体和优化,以适应新的编程范式和技术需求。
核心概念
抽象工厂模式的核心在于定义了一个接口(或抽象类),该接口负责创建一系列相关或相互依赖的对象家族。具体来说,它包含以下几个关键角色:
- 抽象工厂(Abstract Factory):定义了创建一组产品的接口。
- 具体工厂(Concrete Factory):实现了抽象工厂中的接口,负责创建具体的产品实例。
- 抽象产品(Abstract Product):定义了产品的接口。
- 具体产品(Concrete Product):实现了抽象产品接口,是具体工厂创建的对象。
通用实现
java 实现
java
// 抽象产品A
public interface AbstractProductA {
void operationA();
}
// 具体产品A1
public class ConcreteProductA1 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA1 operationA");
}
}
// 具体产品A2
public class ConcreteProductA2 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA2 operationA");
}
}
// 抽象产品B
public interface AbstractProductB {
void operationB();
}
// 具体产品B1
public class ConcreteProductB1 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB1 operationB");
}
}
// 具体产品B2
public class ConcreteProductB2 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB2 operationB");
}
}
// 抽象工厂
public interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
// 客户端代码
public class Client {
private AbstractProductA productA;
private AbstractProductB productB;
public Client(AbstractFactory factory) {
productA = factory.createProductA();
productB = factory.createProductB();
}
public void run() {
productA.operationA();
productB.operationB();
}
public static void main(String[] args) {
// 使用具体工厂1
AbstractFactory factory1 = new ConcreteFactory1();
Client client1 = new Client(factory1);
client1.run();
// 使用具体工厂2
AbstractFactory factory2 = new ConcreteFactory2();
Client client2 = new Client(factory2);
client2.run();
}
}php 实现
php
// 抽象产品A
interface AbstractProductA {
public function operationA();
}
// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {
public function operationA() {
echo "ConcreteProductA1 operationA\n";
}
}
// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {
public function operationA() {
echo "ConcreteProductA2 operationA\n";
}
}
// 抽象产品B
interface AbstractProductB {
public function operationB();
}
// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {
public function operationB() {
echo "ConcreteProductB1 operationB\n";
}
}
// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {
public function operationB() {
echo "ConcreteProductB2 operationB\n";
}
}
// 抽象工厂
interface AbstractFactory {
public function createProductA(): AbstractProductA;
public function createProductB(): AbstractProductB;
}
// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
public function createProductA(): AbstractProductA {
return new ConcreteProductA1();
}
public function createProductB(): AbstractProductB {
return new ConcreteProductB1();
}
}
// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
public function createProductA(): AbstractProductA {
return new ConcreteProductA2();
}
public function createProductB(): AbstractProductB {
return new ConcreteProductB2();
}
}
// 客户端代码
class Client {
private $productA;
private $productB;
public function __construct(AbstractFactory $factory) {
$this->productA = $factory->createProductA();
$this->productB = $factory->createProductB();
}
public function run() {
$this->productA->operationA();
$this->productB->operationB();
}
}
// 使用具体工厂1
$factory1 = new ConcreteFactory1();
$client1 = new Client($factory1);
$client1->run();
// 使用具体工厂2
$factory2 = new ConcreteFactory2();
$client2 = new Client($factory2);
$client2->run();应用场景
抽象工厂模式适用于以下场景:
- 当需要创建一组相关或相互依赖的对象家族时。
- 当系统需要独立于其产品的创建、组合和表示时。
- 当系统需要配置一组可替换的对象族时。
- 当需要强调一系列相关产品对象的设计以便进行联合使用时。
案例
一个典型的案例是跨平台的应用程序界面(UI)库,其中需要为不同的操作系统(如Windows、MacOS、Linux)提供一致的UI组件(如按钮、文本框等)。每个操作系统都有自己的UI组件实现,但它们必须遵循相同的接口,以便应用程序可以在不同平台上保持一致的行为。
java 实现
java
// 抽象产品:按钮
public interface Button {
void render();
}
// Windows按钮实现
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("Render a Windows button.");
}
}
// MacOS按钮实现
public class MacButton implements Button {
@Override
public void render() {
System.out.println("Render a Mac button.");
}
}
// Linux按钮实现
public class LinuxButton implements Button {
@Override
public void render() {
System.out.println("Render a Linux button.");
}
}
// 抽象产品:文本框
public interface TextBox {
void render();
}
// Windows文本框实现
public class WindowsTextBox implements TextBox {
@Override
public void render() {
System.out.println("Render a Windows text box.");
}
}
// MacOS文本框实现
public class MacTextBox implements TextBox {
@Override
public void render() {
System.out.println("Render a Mac text box.");
}
}
// Linux文本框实现
public class LinuxTextBox implements TextBox {
@Override
public void render() {
System.out.println("Render a Linux text box.");
}
}
// 抽象工厂:UI工厂
public interface UIFactory {
Button createButton();
TextBox createTextBox();
}
// WindowsUI工厂
public class WindowsUIFactory implements UIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
// MacUI工厂
public class MacUIFactory implements UIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
}
// LinuxUI工厂
public class LinuxUIFactory implements UIFactory {
@Override
public Button createButton() {
return new LinuxButton();
}
@Override
public TextBox createTextBox() {
return new LinuxTextBox();
}
}
// 客户端代码
public class Application {
private Button button;
private TextBox textBox;
public Application(UIFactory factory) {
button = factory.createButton();
textBox = factory.createTextBox();
}
public void paint() {
button.render();
textBox.render();
}
public static void main(String[] args) {
String osName = System.getProperty("os.name").toLowerCase();
UIFactory factory;
if (osName.contains("win")) {
factory = new WindowsUIFactory();
} else if (osName.contains("mac")) {
factory = new MacUIFactory();
} else {
factory = new LinuxUIFactory();
}
Application app = new Application(factory);
app.paint();
}
}php 实现
php
// 抽象产品:按钮
interface Button {
public function render();
}
// Windows按钮实现
class WindowsButton implements Button {
public function render() {
echo "Render a Windows button.\n";
}
}
// MacOS按钮实现
class MacButton implements Button {
public function render() {
echo "Render a Mac button.\n";
}
}
// Linux按钮实现
class LinuxButton implements Button {
public function render() {
echo "Render a Linux button.\n";
}
}
// 抽象产品:文本框
interface TextBox {
public function render();
}
// Windows文本框实现
class WindowsTextBox implements TextBox {
public function render() {
echo "Render a Windows text box.\n";
}
}
// MacOS文本框实现
class MacTextBox implements TextBox {
public function render() {
echo "Render a Mac text box.\n";
}
}
// Linux文本框实现
class LinuxTextBox implements TextBox {
public function render() {
echo "Render a Linux text box.\n";
}
}
// 抽象工厂:UI工厂
interface UIFactory {
public function createButton(): Button;
public function createTextBox(): TextBox;
}
// WindowsUI工厂
class WindowsUIFactory implements UIFactory {
public function createButton(): Button {
return new WindowsButton();
}
public function createTextBox(): TextBox {
return new WindowsTextBox();
}
}
// MacUI工厂
class MacUIFactory implements UIFactory {
public function createButton(): Button {
return new MacButton();
}
public function createTextBox(): TextBox {
return new MacTextBox();
}
}
// LinuxUI工厂
class LinuxUIFactory implements UIFactory {
public function createButton(): Button {
return new LinuxButton();
}
public function createTextBox(): TextBox {
return new LinuxTextBox();
}
}
// 客户端代码
class Application {
private $button;
private $textBox;
public function __construct(UIFactory $factory) {
$this->button = $factory->createButton();
$this->textBox = $factory->createTextBox();
}
public function paint() {
$this->button->render();
$this->textBox->render();
}
}
// 根据操作系统选择合适的UI工厂
$osName = strtolower(PHP_OS);
$factory = null;
if (strpos($osName, 'win') !== false) {
$factory = new WindowsUIFactory();
} elseif (strpos($osName, 'darwin') !== false) {
$factory = new MacUIFactory();
} else {
$factory = new LinuxUIFactory();
}
$app = new Application($factory);
$app->paint();优点
- 隔离具体类:抽象工厂模式帮助客户代码隔离具体类,使得客户不需要知道具体类的名字,只需要知道抽象类或接口即可。
- 易于交换产品族:由于具体工厂类在一个应用中只需要初始化一次,因此可以很容易地在运行时切换不同的产品族。
- 保证产品的一致性:当一个系列的产品对象被设计成一起工作时,使用抽象工厂模式可以保证这些产品对象始终在一起工作,不会出现不兼容的情况。
缺点
- 难以支持新的产品等级结构:如果需要向已有的产品族中添加新的产品等级结构,就必须修改抽象工厂的接口,这会导致所有具体工厂类都需要进行修改,违反了开闭原则。
- 增加系统复杂度:引入抽象工厂模式会增加系统的抽象性和理解难度,对于小型项目来说可能会显得过于复杂。
扩展
- 支持新的产品族:通过引入反射机制或配置文件,可以在不修改现有代码的情况下动态加载新的具体工厂类,从而支持新的产品族。
- 结合其他设计模式:
- 单例模式:可以确保一个具体工厂类只有一个实例存在,从而节省系统资源。
- 建造者模式:可以用于创建更复杂的对象,抽象工厂可以负责协调这些建造者。
- 适配器模式:可以在已有工厂的基础上,适配新的产品接口,从而复用已有代码。
- 依赖注入:抽象工厂可以与依赖注入框架结合使用,通过框架管理工厂和产品的生命周期,减少硬编码依赖。
- 插件化架构:抽象工厂模式非常适合用于插件化系统的设计,通过插件动态加载不同的工厂和产品,实现系统的可扩展性。
模式协作
- 与单例模式结合:抽象工厂的实现类可以设计为单例,确保整个系统中使用的是同一个工厂实例,避免重复创建对象。
- 与建造者模式结合:建造者模式负责复杂对象的构建,而抽象工厂负责选择合适的建造者并启动构建过程。
- 与工厂方法模式结合:抽象工厂可以基于工厂方法模式实现,具体工厂通过重写工厂方法来返回具体产品。
- 与原型模式结合:如果产品对象的创建成本较高,可以通过原型模式克隆已有对象,而不是每次都创建新对象。
延伸思考
- 是否真的需要抽象工厂:
- 对于简单的对象创建逻辑,可能不需要使用抽象工厂,直接使用简单工厂或工厂方法即可。
- 抽象工厂更适合多个产品族、多个产品等级的复杂系统。
- 性能与可维护性权衡:
- 虽然抽象工厂提升了系统的可扩展性和一致性,但也会增加类的数量,可能影响性能和维护成本。
- 现代框架中的替代方案:
- 依赖注入(DI)框架可以自动管理对象的创建和组合,很多场景下可以替代抽象工厂。
- 使用Spring(Java)或Symfony(PHP)等框架时,可以通过配置实现类似抽象工厂的功能。
- 未来演进方向:
- 随着函数式编程的发展,可以通过高阶函数和闭包来实现工厂逻辑,减少类的层级。
- 在微服务架构中,抽象工厂可以作为服务发现与配置的一部分,实现跨服务的对象创建逻辑统一。
总结
抽象工厂模式是一种强大的设计模式,适用于需要创建多个相关或相互依赖对象的场景。通过定义一个抽象工厂接口,我们可以将具体类的实例化推迟到具体的工厂类中,从而提高系统的灵活性和可维护性。尽管它有一定的复杂度,但对于大型项目来说,这种模式能够带来显著的好处。