软件设计模式系列之二——抽象工厂模式

1 抽象工厂模式的定义

抽象工厂模式是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的方式,而无需指定它们的具体类。该模式以一组抽象接口为核心,包括抽象工厂接口和一组抽象产品接口,每个具体工厂类负责创建特定产品家族,保证这些产品之间的兼容性。客户端代码通过与抽象工厂和抽象产品接口交互,可以轻松地切换不同工厂来创建不同系列的产品,从而实现高内聚、低耦合的设计。

2 举例说明

抽象工厂模式可以通过小米和华为这两个公司的例子来解释。

抽象工厂: 在抽象工厂模式中,我们首先定义一个抽象工厂,该工厂有多个方法,每个方法负责创建不同类型的产品,例如手机、电脑、手表等。在这个例子中,我们将创建一个AbstractFactory,其中包含了createPhone、createComputer、createWatch等方法,分别用于创建手机、电脑和手表。

具体工厂: 对于每个制造公司(小米和华为),我们会实现具体的工厂类,这些工厂类继承了抽象工厂并实现了其中的方法。例如,小米工厂类会实现createPhone方法以创建小米手机,createComputer方法以创建小米电脑,createWatch方法以创建小米手表。同样,华为工厂类也会有相应的实现。

抽象产品: 为了确保产品之间的兼容性,我们定义一组抽象产品类,如AbstractPhone、AbstractComputer、AbstractWatch等。每个抽象产品类定义了产品的通用接口,例如,AbstractPhone可以有makeCall方法。

具体产品: 每个具体工厂类都会创建特定品牌的产品,例如,小米工厂会创建小米手机、小米电脑、小米手表等。这些具体产品类实现了抽象产品类的接口,例如,XiaomiPhone类实现了AbstractPhone接口的makeCall方法。

客户端: 最后,客户端代码可以选择使用哪个具体工厂(小米或华为工厂),然后通过工厂创建产品。客户端不需要了解具体的产品如何创建,只需使用抽象工厂接口和抽象产品接口。

3 结构

描述抽象工厂模式的核心组件,包括以下组件。

抽象工厂接口(Abstract Factory): 定义了一组方法,每个方法用于创建某一类对象,通常包括多个产品族的创建方法。

具体工厂类(Concrete Factory): 实现了抽象工厂接口,负责创建具体的产品对象。每个具体工厂类通常对应一个产品族。

抽象产品接口(Abstract Product): 定义了一组方法,用于描述产品的通用行为。

具体产品类(Concrete Product): 实现了抽象产品接口,表示真正的产品对象。每个具体产品类属于某个产品族。

4 实现步骤

定义抽象产品接口(Abstract Product)

首先,定义一组抽象产品接口,每个接口代表一个产品族中的产品。这些接口包括一组方法,描述了产品的通用行为。

定义抽象工厂接口(Abstract Factory)

创建一个抽象工厂接口,其中包含多个用于创建不同产品的抽象方法。这个接口定义了一组产品族的创建方法。

创建具体产品类(Concrete Product)

对于每个产品族,创建具体产品类,实现对应的抽象产品接口。每个具体产品类表示一个具体的产品。

创建具体工厂类(Concrete Factory)

创建具体工厂类,实现抽象工厂接口中的方法。每个具体工厂类负责创建特定产品族的产品。这些工厂类通常与具体产品类一一对应。

客户端使用抽象工厂:

在客户端代码中,不直接实例化具体产品类,而是通过抽象工厂接口来创建产品对象。客户端只需与抽象工厂接口进行交互,不需要关心具体的产品创建细节。

5 代码实现

下面的Java示例演示了如何使用抽象工厂模式创建不同品牌(小米和华为)的手机、电脑和手表。客户端代码可以通过切换工厂对象来创建不同品牌的产品,而不需要了解具体产品的细节。这种方式确保了产品之间的兼容性,同时使代码更加灵活和可扩展。

复制代码
// 抽象产品类 - 手机
interface AbstractPhone {
    String makeCall();
}

// 具体产品类 - 小米手机
class XiaomiPhone implements AbstractPhone {
    @Override
    public String makeCall() {
        return "使用小米手机打电话";
    }
}

// 具体产品类 - 华为手机
class HuaweiPhone implements AbstractPhone {
    @Override
    public String makeCall() {
        return "使用华为手机打电话";
    }
}

// 抽象产品类 - 电脑
interface AbstractComputer {
    String compute();
}

// 具体产品类 - 小米电脑
class XiaomiComputer implements AbstractComputer {
    @Override
    public String compute() {
        return "使用小米电脑进行计算";
    }
}

// 具体产品类 - 华为电脑
class HuaweiComputer implements AbstractComputer {
    @Override
    public String compute() {
        return "使用华为电脑进行计算";
    }
}

// 抽象产品类 - 手表
interface AbstractWatch {
    String showTime();
}

// 具体产品类 - 小米手表
class XiaomiWatch implements AbstractWatch {
    @Override
    public String showTime() {
        return "查看小米手表时间";
    }
}

// 具体产品类 - 华为手表
class HuaweiWatch implements AbstractWatch {
    @Override
    public String showTime() {
        return "查看华为手表时间";
    }
}

// 抽象工厂类
interface AbstractFactory {
    AbstractPhone createPhone();
    AbstractComputer createComputer();
    AbstractWatch createWatch();
}

// 具体工厂类 - 小米工厂
class XiaomiFactory implements AbstractFactory {
    @Override
    public AbstractPhone createPhone() {
        return new XiaomiPhone();
    }

    @Override
    public AbstractComputer createComputer() {
        return new XiaomiComputer();
    }

    @Override
    public AbstractWatch createWatch() {
        return new XiaomiWatch();
    }
}

// 具体工厂类 - 华为工厂
class HuaweiFactory implements AbstractFactory {
    @Override
    public AbstractPhone createPhone() {
        return new HuaweiPhone();
    }

    @Override
    public AbstractComputer createComputer() {
        return new HuaweiComputer();
    }

    @Override
    public AbstractWatch createWatch() {
        return new HuaweiWatch();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用小米工厂
        AbstractFactory xiaomiFactory = new XiaomiFactory();
        AbstractPhone xiaomiPhone = xiaomiFactory.createPhone();
        AbstractComputer xiaomiComputer = xiaomiFactory.createComputer();
        AbstractWatch xiaomiWatch = xiaomiFactory.createWatch();

        System.out.println(xiaomiPhone.makeCall());
        System.out.println(xiaomiComputer.compute());
        System.out.println(xiaomiWatch.showTime());

        // 使用华为工厂
        AbstractFactory huaweiFactory = new HuaweiFactory();
        AbstractPhone huaweiPhone = huaweiFactory.createPhone();
        AbstractComputer huaweiComputer = huaweiFactory.createComputer();
        AbstractWatch huaweiWatch = huaweiFactory.createWatch();

        System.out.println(huaweiPhone.makeCall());
        System.out.println(huaweiComputer.compute());
        System.out.println(huaweiWatch.showTime());
    }
}

6 典型应用场景

抽象工厂模式在许多典型应用场景中都非常有用,以下是两个具体的应用场景。

6.1 不同数据库的连接和操作

在软件开发中,经常需要与不同类型的数据库系统进行交互,如MySQL、Oracle、SQL Server等。不同数据库系统具有不同的连接和SQL语句执行方式。在这种情况下,抽象工厂模式可以应用如下:

抽象工厂接口: 定义了创建数据库连接对象和SQL语句执行对象的方法。

具体工厂类: 每个具体数据库系统都有自己的工厂类,实现了抽象工厂接口。例如,MySQLFactory、OracleFactory、SQLServerFactory等工厂类。

抽象产品类: 定义了数据库连接对象和SQL语句执行对象的通用接口,如AbstractConnection和AbstractStatement。

具体产品类: 每个具体数据库系统都有自己的产品类,实现了抽象产品接口,例如MySQLConnection、OracleConnection、SQLServerConnection以及对应的SQL语句执行对象。

使用抽象工厂模式,客户端代码可以选择使用特定的工厂,然后使用该工厂创建数据库连接和SQL语句执行对象,而无需关心不同数据库系统的细节差异。

6.2 不同操作系统的图形界面

在跨平台应用程序开发中,需要适应不同操作系统(如Windows、macOS、Linux)的图形用户界面(GUI)。不同操作系统提供不同的窗口、按钮、文本框等UI组件,以及UI交互行为。抽象工厂模式可以应用如下:

抽象工厂接口: 定义了创建不同操作系统下的UI组件的方法,如AbstractWindowFactory、AbstractButtonFactory等。

具体工厂类: 为每个操作系统创建具体工厂类,实现了抽象工厂接口,如WindowsFactory、MacOSFactory、LinuxFactory。

抽象产品类: 定义了不同UI组件的通用接口,如AbstractWindow、AbstractButton等。

具体产品类: 每个具体操作系统都有自己的产品类,实现了抽象产品接口,例如WindowsWindow、MacOSWindow、LinuxWindow,以及对应的按钮等。

使用抽象工厂模式,应用程序可以在运行时选择合适的工厂,以确保在不同操作系统上拥有一致的UI体验,同时不需要关心底层UI组件的创建和差异。

7 优缺点

优点

抽象性和灵活性: 抽象工厂模式封装了对象的创建过程,使客户端代码与具体类解耦。客户端只需要依赖于抽象接口,可以轻松切换不同的产品族,而不影响客户端代码。

一致性保证: 抽象工厂模式确保了一组相关产品的一致性,因为它们由同一个工厂创建。

符合开闭原则: 向系统中添加新的产品族是相对容易的,而不需要修改现有代码,符合开闭原则。

缺点

复杂性增加: 抽象工厂模式引入了多个抽象类和接口,可能增加了系统的复杂性。

不易扩展新产品: 如果需要添加新的产品种类,必须同时扩展抽象工厂接口和所有具体工厂类,这可能导致一定的工作量。

产品族之间的扩展困难: 如果需要扩展现有产品族,可能需要修改多个工厂类,使其支持新的产品。

8 类似模式

抽象工厂模式、工厂方法模式和简单工厂模式都是创建型设计模式,用于对象的创建,但它们在解决不同问题和应用场景中有不同的角色和关系。

简单工厂模式: 简单工厂模式是最基本的工厂模式,它通过一个工厂类来创建不同类型的对象,根据传入的参数或条件决定创建哪种具体产品。它适用于创建单一类型的对象,但缺乏扩展性和灵活性。

工厂方法模式: 工厂方法模式引入了多个具体工厂类,每个具体工厂类负责创建一种具体产品,客户端通过与抽象工厂接口交互,选择使用哪个具体工厂来创建对象。这种模式支持多个产品类型的扩展,但需要客户端知道所使用的工厂类。

抽象工厂模式: 抽象工厂模式进一步抽象了工厂方法模式,引入了多个抽象产品家族和多个具体工厂类。它用于创建一组相关的产品对象,确保这些对象之间的一致性和兼容性。客户端代码与具体产品无关,只需与抽象工厂和抽象产品接口交互。

关系总结:抽象工厂模式是工厂方法模式的扩展,而工厂方法模式又是简单工厂模式的扩展。它们的使用场景逐渐从单一对象创建到多个相关对象的创建,从而提供了更多的灵活性和可扩展性。选择哪种模式取决于具体需求和设计目标。

9 小结

总之,抽象工厂模式通过提供一个接口来封装对象的创建过程,使得系统更加灵活、可扩展,同时确保了相关对象之间的一致性。这有助于降低代码的耦合度,并促进了面向接口编程的实践

相关推荐
杨充17 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充18 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充18 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充18 小时前
2.面向对象的特性
设计模式
杨充18 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充18 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充18 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯21 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式