模式定义

抽象工厂模式是一种创建型设计模式,它能创建一系列相关的对象而无需指定其具体类。抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

适用场景

结构图

graph TD A[AbstractFactory] --> B{createProductA} A --> C{createProductB} D[ConcreteFactory1] --> E{createProductA1} D --> F{createProductB1} G[ConcreteFactory2] --> H{createProductA2} G --> I{createProductB2} J[Client] --> A

实现示例

Java 实现

// 抽象产品A
public interface ProductA {
    void useA();
}

// 抽象产品B
public interface ProductB {
    void useB();
}

// 具体产品A1
public class ProductA1 implements ProductA {
    @Override
    public void useA() {
        System.out.println("使用产品A1");
    }
}

// 具体产品A2
public class ProductA2 implements ProductA {
    @Override
    public void useA() {
        System.out.println("使用产品A2");
    }
}

// 具体产品B1
public class ProductB1 implements ProductB {
    @Override
    public void useB() {
        System.out.println("使用产品B1");
    }
}

// 具体产品B2
public class ProductB2 implements ProductB {
    @Override
    public void useB() {
        System.out.println("使用产品B2");
    }
}

// 抽象工厂
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }
    
    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }
    
    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}
                

经典案例

1. Java SE中的抽象工厂模式

Java标准库中的许多地方都使用了抽象工厂模式,例如JDBC API:

// DriverManager是抽象工厂的客户端
public class JdbcExample {
    public static void main(String[] args) {
        try {
            // 通过抽象工厂创建具体的数据库连接
            Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/test", "user", "password");
            
            // 创建Statement对象
            Statement stmt = conn.createStatement();
            
            // 执行查询
            ResultSet rs = stmt.executeQuery("SELECT * FROM users");
            
            // 处理结果
            while (rs.next()) {
                System.out.println(rs.getString("name"));
            }
            
            // 关闭资源
            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

// DriverManager内部使用了抽象工厂模式
// 不同的数据库厂商提供具体的工厂实现
// 例如MySQL的com.mysql.cj.jdbc.Driver
// 例如PostgreSQL的org.postgresql.Driver

2. Spring框架中的抽象工厂应用

Spring框架中也大量使用了抽象工厂模式的思想:

// Spring中的BeanFactory就是抽象工厂模式的体现
public interface BeanFactory {
    Object getBean(String name) throws BeansException;
     T getBean(String name, Class requiredType) throws BeansException;
     T getBean(Class requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    // ... 其他方法
}

// 不同的工厂实现
// DefaultListableBeanFactory
// XmlBeanFactory
// AnnotationConfigApplicationContext
// 等等都是具体的工厂实现

// 使用示例
@Configuration
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        // 返回具体的数据源实现
        return new HikariDataSource();
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate() {
        // 使用工厂方法创建JdbcTemplate
        return new JdbcTemplate(dataSource());
    }
}

3. 跨平台UI工具包

跨平台UI工具包是抽象工厂模式的经典应用场景:

// 抽象产品接口
public interface Button {
    void render();
    void onClick();
}

public interface Checkbox {
    void render();
    void toggle();
}

// Windows具体产品
public class WindowsButton implements Button {
    public void render() {
        System.out.println("渲染Windows风格按钮");
    }
    
    public void onClick() {
        System.out.println("Windows按钮被点击");
    }
}

public class WindowsCheckbox implements Checkbox {
    public void render() {
        System.out.println("渲染Windows风格复选框");
    }
    
    public void toggle() {
        System.out.println("Windows复选框状态切换");
    }
}

// Mac具体产品
public class MacButton implements Button {
    public void render() {
        System.out.println("渲染Mac风格按钮");
    }
    
    public void onClick() {
        System.out.println("Mac按钮被点击");
    }
}

public class MacCheckbox implements Checkbox {
    public void render() {
        System.out.println("渲染Mac风格复选框");
    }
    
    public void toggle() {
        System.out.println("Mac复选框状态切换");
    }
}

// 抽象工厂
public interface UIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

// Windows工厂
public class WindowsFactory implements UIFactory {
    public Button createButton() {
        return new WindowsButton();
    }
    
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

// Mac工厂
public class MacFactory implements UIFactory {
    public Button createButton() {
        return new MacButton();
    }
    
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

// 应用程序类
public class Application {
    private Button button;
    private Checkbox checkbox;
    
    public Application(UIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }
    
    public void paint() {
        button.render();
        checkbox.render();
    }
    
    public void clickButton() {
        button.onClick();
    }
    
    public void toggleCheckbox() {
        checkbox.toggle();
    }
}

// 客户端代码
public class ApplicationRunner {
    public static void main(String[] args) {
        UIFactory factory;
        String osName = System.getProperty("os.name").toLowerCase();
        
        if (osName.contains("win")) {
            factory = new WindowsFactory();
        } else if (osName.contains("mac")) {
            factory = new MacFactory();
        } else {
            // 默认工厂
            factory = new WindowsFactory();
        }
        
        Application app = new Application(factory);
        app.paint();
        app.clickButton();
        app.toggleCheckbox();
    }
}

优缺点

优点

  • 确保客户端始终只使用同一个产品族中的对象
  • 易于交换产品系列,只需更换具体工厂即可
  • 有利于产品的一致性,保证产品间的约束关系

缺点

  • 难以支持新种类的产品,扩展新产品需要修改抽象工厂接口
  • 增加了系统的抽象性和复杂度