设计模式之抽象工厂模式

2024-06-03 08:30:10 浏览数 (2)

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

概述

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

定义

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

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

    @Override
    public MobilePhone makeMobilePhone() {
        return new IPhone();
    }
}
代码语言:javascript复制
public class XiaoMiFactory implements AbstractFactory {
    @Override
    public Computer makeComputer() {
        return new MiComputer();
    }

    @Override
    public MobilePhone makeMobilePhone() {
        return new MiPhone();
    }
}
使用示例
代码语言:javascript复制
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();
    }
}

输出:

代码语言:javascript复制
Mac笔记本
苹果手机
小米笔记本
小米手机
相互依赖对象

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

抽象产品类
代码语言:javascript复制
public interface Computer {
    OperatingSystem getOperatingSystem();
    void setOperatingSystem(OperatingSystem operatingSystem);
    void displayInfo();
}
代码语言:javascript复制
public interface OperatingSystem {
    String getInfo();
}
具体产品类
代码语言:javascript复制
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());
    }
}
代码语言:javascript复制
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());
    }
}
代码语言:javascript复制
public class MacOS implements OperatingSystem {
    @Override
    public String getInfo() {
        return "MacOS";
    }
}
代码语言:javascript复制
public class WindowsOS implements OperatingSystem {
    @Override
    public String getInfo() {
        return "WindowsOS";
    }
}
抽象工厂接口
代码语言:javascript复制
public interface AbstractFactory {
    Computer createComputer();
    OperatingSystem createOperatingSystem();
}
具体工厂类
代码语言:javascript复制
public class MacFactory implements AbstractFactory {
    @Override
    public Computer createComputer() {
        return new MacComputer();
    }

    @Override
    public OperatingSystem createOperatingSystem() {
        return new MacOS();
    }
}
代码语言:javascript复制
public class WindowsFactory implements AbstractFactory {
    @Override
    public Computer createComputer() {
        return new WindowsComputer();
    }

    @Override
    public OperatingSystem createOperatingSystem() {
        return new WindowsOS();
    }
}
客户端代码
代码语言:javascript复制
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();
    }
}

输出:

代码语言:javascript复制
Windows computer 安装 WindowsOS
Mac computer 安装 MacOS
工作中遇到的场景

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

示例场景:跨平台UI库

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

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


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

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}
代码语言:javascript复制
public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacTextBox();
    }
}
客户端代码
代码语言:javascript复制
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();
    }
}

输出:

代码语言:javascript复制
绘制 Windows 风格按钮
绘制 Windows 风格文本框
绘制 Mac 风格按钮
绘制 Mac 风格文本框

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

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

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

建造者模式

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

实际案例分析
案例一:跨平台文件系统

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

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

    @Override
    public FileWriter createFileWriter() {
        return new WindowsFileWriter();
    }
}
代码语言:javascript复制
public class LinuxFileSystemFactory implements FileSystemFactory {
    @Override
    public FileReader createFileReader() {
        return new LinuxFileReader();
    }

    @Override
    public FileWriter createFileWriter() {
        return new LinuxFileWriter();
    }
}
客户端代码
代码语言:javascript复制
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();
    }
}

输出:

代码语言:javascript复制
读取 Windows 文件
写入 Windows 文件
读取 Linux 文件
写入 Linux 文件

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

其他示例和应用场景
游戏开发中的抽象工厂模式

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

抽象产品类
代码语言:javascript复制
public interface Character {
    void render();
}
代码语言:javascript复制
public interface Weapon {
    void attack();
}
具体产品类
代码语言:javascript复制
public class MedievalCharacter implements Character {
    @Override
    public void render() {
        System.out.println("渲染中世纪角色");
    }
}
代码语言:javascript复制
public class FuturisticCharacter implements Character {
    @Override
    public void render() {
        System.out.println("渲染未来角色");
    }
}
代码语言:javascript复制
public class Sword implements Weapon {
    @Override
    public void attack() {
        System.out.println("使用剑攻击");
    }
}
代码语言:javascript复制
public class LaserGun implements Weapon {
    @Override
    public void attack() {
        System.out.println("使用激光枪攻击");
    }
}
抽象工厂接口
代码语言:javascript复制
public interface GameElementFactory {
    Character createCharacter();
    Weapon createWeapon();
}
具体工厂类
代码语言:javascript复制
public class MedievalGameElementFactory implements GameElementFactory {
    @Override
    public Character createCharacter() {
        return new MedievalCharacter();
    }

    @Override
    public Weapon createWeapon() {
        return new Sword();
    }
}
代码语言:javascript复制
public class FuturisticGameElementFactory implements GameElementFactory {
    @Override
    public Character createCharacter() {
        return new FuturisticCharacter();
    }

    @Override
    public Weapon createWeapon() {
        return new LaserGun();
    }
}
客户端代码
代码语言:javascript复制
public class Client {
    public static void main(String[] args) {
        GameElementFactory medievalFactory = new MedievalGameElementFactory();
        Character medievalCharacter = medievalFactory.createCharacter();
        Weapon sword = medievalFactory.createWeapon();
        medievalCharacter.render();
        sword.attack();

        GameElementFactory futuristicFactory = new FuturisticGameElementFactory();
        Character futuristicCharacter = futuristicFactory.createCharacter();
        Weapon laserGun = futuristicFactory.createWeapon();
        futuristicCharacter.render();
        laserGun.attack();
    }
}

输出:

代码语言:javascript复制
渲染中世纪角色
使用剑攻击
渲染未来角色
使用激光枪攻击

通过抽象工厂模式,游戏开发者可以方便地在不同的游戏场景之间切换元素组合,提升开发效率和代码的可维护性。

数据库访问层的抽象工厂模式

在企业应用中,不同的数据库系统(如MySQL、Oracle、SQL Server)可能有不同的访问方式和SQL方言。通过抽象工厂模式,可以为不同的数据库系统提供统一的访问接口,从而提高系统的可移植性。

抽象产品类
代码语言:javascript复制
public interface Connection {
    void connect();
}
代码语言:javascript复制
public interface Query {
    void execute();
}
具体产品类
代码语言:javascript复制
public class MySQLConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接到 MySQL 数据

库");
    }
}
代码语言:javascript复制
public class OracleConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接到 Oracle 数据库");
    }
}
代码语言:javascript复制
public class MySQLQuery implements Query {
    @Override
    public void execute() {
        System.out.println("执行 MySQL 查询");
    }
}
代码语言:javascript复制
public class OracleQuery implements Query {
    @Override
    public void execute() {
        System.out.println("执行 Oracle 查询");
    }
}
抽象工厂接口
代码语言:javascript复制
public interface DatabaseFactory {
    Connection createConnection();
    Query createQuery();
}
具体工厂类
代码语言:javascript复制
public class MySQLDatabaseFactory implements DatabaseFactory {
    @Override
    public Connection createConnection() {
        return new MySQLConnection();
    }

    @Override
    public Query createQuery() {
        return new MySQLQuery();
    }
}
代码语言:javascript复制
public class OracleDatabaseFactory implements DatabaseFactory {
    @Override
    public Connection createConnection() {
        return new OracleConnection();
    }

    @Override
    public Query createQuery() {
        return new OracleQuery();
    }
}
客户端代码
代码语言:javascript复制
public class Client {
    public static void main(String[] args) {
        DatabaseFactory mysqlFactory = new MySQLDatabaseFactory();
        Connection mysqlConnection = mysqlFactory.createConnection();
        Query mysqlQuery = mysqlFactory.createQuery();
        mysqlConnection.connect();
        mysqlQuery.execute();

        DatabaseFactory oracleFactory = new OracleDatabaseFactory();
        Connection oracleConnection = oracleFactory.createConnection();
        Query oracleQuery = oracleFactory.createQuery();
        oracleConnection.connect();
        oracleQuery.execute();
    }
}

输出:

代码语言:javascript复制
连接到 MySQL 数据库
执行 MySQL 查询
连接到 Oracle 数据库
执行 Oracle 查询

通过抽象工厂模式,可以为不同的数据库系统提供统一的访问接口,从而提高系统的可移植性和可维护性。

总结

抽象工厂模式是一种强大的设计模式,它通过提供创建一系列相关或相互依赖对象的接口,解耦了客户端代码与具体产品类,从而提高了系统的灵活性和可扩展性。在实际开发中,抽象工厂模式广泛应用于需要创建多个相关对象的场景,如跨平台应用、游戏开发和数据库访问层等。通过合理地运用抽象工厂模式,开发者可以有效地管理和扩展系统,提高代码的可维护性和可复用性。

0 人点赞