设计模式之抽象工厂模式

时间:2024-06-07 21:04:20

抽象工厂模式(Abstract Factory)是一种创建型设计模式,提供一个接口用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。该模式的主要角色包括抽象工厂、具体工厂、抽象产品和具体产品。抽象工厂声明创建产品的方法,具体工厂实现这些方法生成具体的产品实例。抽象产品定义产品的接口,具体产品实现这些接口。此模式适用于需要创建一系列相关对象且系统需要独立于这些对象的创建和表示的场景。在实际应用中,抽象工厂模式可以用于跨平台UI组件库的设计,确保不同平台的UI组件风格一致。例如,通过不同的具体工厂创建

概述

抽象工厂模式(Abstract Factory)是一种创建型设计模式,它提供一个接口来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。这种模式通过定义一个创建对象的接口,客户端可以使用这个接口创建一组相关的对象,具体的实现细节由子类决定。

定义

抽象工厂模式定义了一个接口,用于创建一组相关或依赖对象的家族,而无需明确指定具体类。通过这种模式,客户端代码可以与具体类解耦,使得代码更加灵活和可扩展。

使用场景
  1. 系统独立于产品创建:当一个系统要独立于它的产品创建、组合和表示时,使用抽象工厂模式可以屏蔽具体产品类的细节。
  2. 多产品族创建:当一个系统需要配置多个产品系列中的一个时,抽象工厂模式允许客户端在产品系列之间切换。
  3. 产品间的相互依赖:当多个产品之间存在依赖关系时,抽象工厂模式确保产品的一致性。
主要角色
  1. 抽象工厂(Abstract Factory):声明创建抽象产品对象的操作。
  2. 具体工厂(Concrete Factory):实现创建具体产品对象的操作。
  3. 抽象产品(Abstract Product):为每种产品对象声明接口。
  4. 具体产品(Concrete Product):定义具体工厂创建的具体产品对象,实现抽象产品接口。
示例代码
抽象产品类
public abstract class Computer {
    public abstract void productIntroduction();
}
public abstract class MobilePhone {
    public abstract void productIntroduction();
}
具体产品类
public class MacComputer extends Computer {
    @Override
    public void productIntroduction() {
        System.out.println("Mac笔记本");
    }
}
public class MiComputer extends Computer {
    @Override
    public void productIntroduction() {
        System.out.println("小米笔记本");
    }
}
public class IPhone extends MobilePhone {
    @Override
    public void productIntroduction() {
        System.out.println("苹果手机");
    }
}
public class MiPhone extends MobilePhone {
    @Override
    public void productIntroduction() {
        System.out.println("小米手机");
    }
}
抽象工厂接口
public interface AbstractFactory {
    Computer makeComputer();
    MobilePhone makeMobilePhone();
}
具体工厂类
public class AppleFactory implements AbstractFactory {
    @Override
    public Computer makeComputer() {
        return new MacComputer();
    }

    @Override
    public MobilePhone makeMobilePhone() {
        return new IPhone();
    }
}
public class XiaoMiFactory implements AbstractFactory {
    @Override
    public Computer makeComputer() {
        return new MiComputer();
    }

    @Override
    public MobilePhone makeMobilePhone() {
        return new MiPhone();
    }
}
使用示例
public class Client {
    public static void main(String[] args) {
        AbstractFactory appleFactory = new AppleFactory();
        Computer mac = appleFactory.makeComputer();
        MobilePhone iphone = appleFactory.makeMobilePhone();
        mac.productIntroduction();
        iphone.productIntroduction();

        AbstractFactory xiaomiFactory = new XiaoMiFactory();
        Computer miComputer = xiaomiFactory.makeComputer();
        MobilePhone miPhone = xiaomiFactory.makeMobilePhone();
        miComputer.productIntroduction();
        miPhone.productIntroduction();
    }
}

输出:

Mac笔记本
苹果手机
小米笔记本
小米手机

相互依赖对象

在一些情况下,产品之间可能存在依赖关系,例如,电脑和操作系统。

抽象产品类
public interface Computer {
    OperatingSystem getOperatingSystem();
    void setOperatingSystem(OperatingSystem operatingSystem);
    void displayInfo();
}
public interface OperatingSystem {
    String getInfo();
}
具体产品类
public class MacComputer implements Computer {
    private OperatingSystem operatingSystem;

    @Override
    public OperatingSystem getOperatingSystem() {
        return operatingSystem;
    }

    @Override
    public void setOperatingSystem(OperatingSystem operatingSystem) {
        this.operatingSystem = operatingSystem;
    }

    @Override
    public void displayInfo() {
        System.out.println("Mac computer 安装 " + operatingSystem.getInfo());
    }
}
public class WindowsComputer implements Computer {
    private OperatingSystem operatingSystem;

    @Override
    public OperatingSystem getOperatingSystem() {
        return operatingSystem;
    }

    @Override
    public void setOperatingSystem(OperatingSystem operatingSystem) {
        this.operatingSystem = operatingSystem;
    }

    @Override
    public void displayInfo() {
        System.out.println("Windows computer 安装 " + operatingSystem.getInfo());
    }
}
public class MacOS implements OperatingSystem {
    @Override
    public String getInfo() {
        return "MacOS";
    }
}
public class WindowsOS implements OperatingSystem {
    @Override
    public String getInfo() {
        return "WindowsOS";
    }
}
抽象工厂接口
public interface AbstractFactory {
    Computer createComputer();
    OperatingSystem createOperatingSystem();
}
具体工厂类
public class MacFactory implements AbstractFactory {
    @Override
    public Computer createComputer() {
        return new MacComputer();
    }

    @Override
    public OperatingSystem createOperatingSystem() {
        return new MacOS();
    }
}
public class WindowsFactory implements AbstractFactory {
    @Override
    public Computer createComputer() {
        return new WindowsComputer();
    }

    @Override
    public OperatingSystem createOperatingSystem() {
        return new WindowsOS();
    }
}
客户端代码
public class Client {
    public static void main(String[] args) {
        AbstractFactory windowsFactory = new WindowsFactory();
        OperatingSystem windowsOS = windowsFactory.createOperatingSystem();
        Computer windowsComputer = windowsFactory.createComputer();
        windowsComputer.setOperatingSystem(windowsOS);
        windowsComputer.displayInfo();

        AbstractFactory macFactory = new MacFactory();
        OperatingSystem macOS = macFactory.createOperatingSystem();
        Computer macComputer = macFactory.createComputer();
        macComputer.setOperatingSystem(macOS);
        macComputer.displayInfo();
    }
}

输出:

Windows computer 安装 WindowsOS
Mac computer 安装 MacOS

工作中遇到的场景

在实际工作中,抽象工厂模式常常用于创建一组相关的对象,而这些对象可能需要根据具体环境进行不同的配置。例如,创建不同品牌的电子产品(如电脑和手机)时,可以使用抽象工厂模式来实现产品族的生产。

示例场景:跨平台UI库

假设我们需要创建一个跨平台的UI库,该库需要支持不同操作系统的UI组件,例如按钮和文本框。在这种情况下,可以使用抽象工厂模式来创建相应的UI组件。

抽象产品类
public interface Button {
    void paint();
}
public interface TextBox {
    void paint();
}
具体产品类
public class WindowsButton implements Button {
    @Override
    public void paint() {
        System.out.println("绘制 Windows 风格按钮");
    }
}
public class MacButton implements Button {
    @Override
    public void paint() {
        System.out.println("绘制 Mac 风格按钮");
    }
}
public class WindowsTextBox implements TextBox {
    @Override
    public void paint() {
        System.out.println("绘制 Windows 风格文本框");
    }
}
public class MacTextBox implements TextBox {
    @Override
    public void paint() {
        System.out.println("绘制 Mac 风格文本框");
    }
}
抽象工厂接口
public interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}
具体工厂类
public class WindowsFactory implements GUIFactory {


    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}
public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacTextBox();
    }
}
客户端代码
public class Client {
    private Button button;
    private TextBox textBox;

    public Client(GUIFactory factory) {
        button = factory.createButton();
        textBox = factory.createTextBox();
    }

    public void paint() {
        button.paint();
        textBox.paint();
    }

    public static void main(String[] args) {
        Client windowsClient = new Client(new WindowsFactory());
        windowsClient.paint();

        Client macClient = new Client(new MacFactory());
        macClient.paint();
    }
}

输出:

绘制 Windows 风格按钮
绘制 Windows 风格文本框
绘制 Mac 风格按钮
绘制 Mac 风格文本框

通过抽象工厂模式,客户端代码可以根据不同的具体工厂实例创建相应风格的UI组件,从而实现跨平台的UI设计。这种模式在大型系统开发中尤为常见,特别是在需要支持多种平台或环境的情况下。

深入分析抽象工厂模式

优点
  1. 分离接口和实现:抽象工厂模式将客户端代码与具体的产品类解耦,客户端通过抽象接口来使用产品,具体的产品类由工厂决定。这种分离增强了系统的灵活性和可扩展性。
  2. 一致的产品族:抽象工厂模式确保了同一产品族中的对象的一致性。例如,同一系列的UI组件在外观和行为上保持一致,避免了不同产品混用造成的不兼容问题。
  3. 易于扩展:新增一个产品族时,只需添加一个具体工厂类,无需修改现有代码,符合开闭原则(Open/Closed Principle)。
缺点
  1. 复杂性增加:抽象工厂模式引入了多个接口和类,增加了系统的复杂性,可能会带来额外的开发和维护成本。
  2. 扩展困难:虽然新增产品族比较容易,但如果需要在已有产品族中新增产品类型,则需要修改抽象工厂和所有具体工厂的接口,违背了开闭原则。

抽象工厂模式与其他设计模式的关系

工厂方法模式

工厂方法模式是抽象工厂模式的一种特例。工厂方法模式只提供一个创建产品的方法,而抽象工厂模式可以提供多个创建产品的方法。抽象工厂模式通常用工厂方法模式来实现产品的创建。

建造者模式

建造者模式关注的是一步步构建一个复杂对象,通常需要一步步地调用不同的方法来创建对象的不同部分。而抽象工厂模式是创建一系列相关或相互依赖的对象。两者的侧重点不同,但在某些情况下,可以结合使用这两种模式来构建复杂对象。

实际案例分析

案例一:跨平台文件系统

在开发一个跨平台的文件系统时,我们需要支持不同操作系统的文件操作。例如,在Windows系统下,我们可能需要提供不同的文件读取和写入实现,而在Linux系统下,可能需要提供另一种实现。

抽象产品类
public interface FileReader {
    void readFile();
}
public interface FileWriter {
    void writeFile();
}
具体产品类
public class WindowsFileReader implements FileReader {
    @Override
    public void readFile() {
        System.out.println("读取 Windows 文件");
    }
}
public class WindowsFileWriter implements FileWriter {
    @Override
    public void writeFile() {
        System.out.println("写入 Windows 文件");
    }
}
public class LinuxFileReader implements FileReader {
    @Override
    public void readFile() {
        System.out.println("读取 Linux 文件");
    }
}
public class LinuxFileWriter implements FileWriter {
    @Override
    public void writeFile() {
        System.out.println("写入 Linux 文件");
    }
}
抽象工厂接口
public interface FileSystemFactory {
    FileReader createFileReader();
    FileWriter createFileWriter();
}
具体工厂类
public class WindowsFileSystemFactory implements FileSystemFactory {
    @Override
    public FileReader createFileReader() {
        return new WindowsFileReader();
    }

    @Override
    public FileWriter createFileWriter() {
        return new WindowsFileWriter();
    }
}
public class LinuxFileSystemFactory implements FileSystemFactory {
    @Override
    public FileReader createFileReader() {
        return new LinuxFileReader();
    }

    @Override
    public FileWriter createFileWriter() {
        return new LinuxFileWriter();
    }
}
客户端代码
public class Client {
    public static void main(String[] args) {
        FileSystemFactory windowsFactory = new WindowsFileSystemFactory();
        FileReader windowsReader = windowsFactory.createFileReader();
        FileWriter windowsWriter = windowsFactory.createFileWriter();
        windowsReader.readFile();
        windowsWriter.writeFile();

        FileSystemFactory linuxFactory = new LinuxFileSystemFactory();
        FileReader linuxReader = linuxFactory.createFileReader();
        FileWriter linuxWriter = linuxFactory.createFileWriter();
        linuxReader.readFile();
        linuxWriter.writeFile();
    }
}

输出:

读取 Windows 文件
写入 Windows 文件
读取 Linux 文件
写入 Linux 文件

通过抽象工厂模式,我们可以轻松地在不同操作系统之间切换文件系统的实现,而无需修改客户端代码。

其他示例和应用场景

游戏开发中的抽象工厂模式

在游戏开发中,抽象工厂模式常用于创建不同类型的游戏元素,例如角色、武器和道具。不同的游戏场景可能需要不同的元素组合,通过抽象工厂模式,可以灵活地创建和管理这些元素。

抽象产品类
public interface Character {
    void render();
}
public interface Weapon {
    void attack();
}