Skip to content

工厂模式

基础概念

什么是工厂模式?

答案: 工厂模式(Factory Pattern)是一种创建型设计模式,提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。

使用场景

  • 对象创建逻辑复杂
  • 需要根据不同条件创建不同对象
  • 解耦对象的创建和使用

优点

  • 解耦,将对象的创建和使用分离
  • 符合开闭原则,扩展性好
  • 符合单一职责原则

缺点

  • 增加系统复杂度
  • 增加类的数量

简单工厂模式

简单工厂的实现?

答案:

java
// 产品接口
public interface Product {
    void use();
}

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

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

// 简单工厂
public class SimpleFactory {
    public static Product createProduct(String type) {
        switch (type) {
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
                throw new IllegalArgumentException("未知产品类型: " + type);
        }
    }
}

// 使用
public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.use();

        Product productB = SimpleFactory.createProduct("B");
        productB.use();
    }
}

优点

  • 实现简单
  • 客户端无需知道具体产品类名

缺点

  • 违反开闭原则,新增产品需要修改工厂类
  • 工厂类职责过重

简单工厂的实际应用?

答案:

示例1:支付工厂

java
// 支付接口
public interface Payment {
    void pay(BigDecimal amount);
}

// 支付宝支付
public class AlipayPayment implements Payment {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("支付宝支付: " + amount);
    }
}

// 微信支付
public class WechatPayment implements Payment {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("微信支付: " + amount);
    }
}

// 银行卡支付
public class BankCardPayment implements Payment {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("银行卡支付: " + amount);
    }
}

// 支付工厂
public class PaymentFactory {
    public static Payment createPayment(String type) {
        switch (type) {
            case "alipay":
                return new AlipayPayment();
            case "wechat":
                return new WechatPayment();
            case "bankcard":
                return new BankCardPayment();
            default:
                throw new IllegalArgumentException("不支持的支付方式: " + type);
        }
    }
}

// 使用
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(new BigDecimal("100.00"));

示例2:日志工厂

java
public interface Logger {
    void log(String message);
}

public class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("写入文件: " + message);
    }
}

public class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("控制台输出: " + message);
    }
}

public class DatabaseLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("写入数据库: " + message);
    }
}

public class LoggerFactory {
    public static Logger createLogger(String type) {
        switch (type) {
            case "file":
                return new FileLogger();
            case "console":
                return new ConsoleLogger();
            case "database":
                return new DatabaseLogger();
            default:
                return new ConsoleLogger();  // 默认控制台
        }
    }
}

工厂方法模式

工厂方法的实现?

答案:

java
// 产品接口
public interface Product {
    void use();
}

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

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

// 工厂接口
public interface Factory {
    Product createProduct();
}

// 具体工厂A
public class FactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

// 具体工厂B
public class FactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

// 使用
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new FactoryA();
        Product productA = factoryA.createProduct();
        productA.use();

        Factory factoryB = new FactoryB();
        Product productB = factoryB.createProduct();
        productB.use();
    }
}

优点

  • 符合开闭原则,新增产品只需新增工厂类
  • 符合单一职责原则,每个工厂只负责创建一种产品

缺点

  • 类的数量增加
  • 增加系统复杂度

工厂方法的实际应用?

答案:

示例1:数据库连接工厂

java
// 数据库连接接口
public interface Connection {
    void connect();
    void execute(String sql);
}

// MySQL连接
public class MySQLConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接MySQL数据库");
    }

    @Override
    public void execute(String sql) {
        System.out.println("MySQL执行: " + sql);
    }
}

// Oracle连接
public class OracleConnection implements Connection {
    @Override
    public void connect() {
        System.out.println("连接Oracle数据库");
    }

    @Override
    public void execute(String sql) {
        System.out.println("Oracle执行: " + sql);
    }
}

// 连接工厂接口
public interface ConnectionFactory {
    Connection createConnection();
}

// MySQL工厂
public class MySQLConnectionFactory implements ConnectionFactory {
    @Override
    public Connection createConnection() {
        return new MySQLConnection();
    }
}

// Oracle工厂
public class OracleConnectionFactory implements ConnectionFactory {
    @Override
    public Connection createConnection() {
        return new OracleConnection();
    }
}

// 使用
ConnectionFactory factory = new MySQLConnectionFactory();
Connection connection = factory.createConnection();
connection.connect();
connection.execute("SELECT * FROM users");

示例2:消息发送工厂

java
// 消息接口
public interface Message {
    void send(String content, String recipient);
}

// 邮件消息
public class EmailMessage implements Message {
    @Override
    public void send(String content, String recipient) {
        System.out.println("发送邮件到 " + recipient + ": " + content);
    }
}

// 短信消息
public class SmsMessage implements Message {
    @Override
    public void send(String content, String recipient) {
        System.out.println("发送短信到 " + recipient + ": " + content);
    }
}

// 微信消息
public class WechatMessage implements Message {
    @Override
    public void send(String content, String recipient) {
        System.out.println("发送微信到 " + recipient + ": " + content);
    }
}

// 消息工厂接口
public interface MessageFactory {
    Message createMessage();
}

// 邮件工厂
public class EmailMessageFactory implements MessageFactory {
    @Override
    public Message createMessage() {
        return new EmailMessage();
    }
}

// 短信工厂
public class SmsMessageFactory implements MessageFactory {
    @Override
    public Message createMessage() {
        return new SmsMessage();
    }
}

// 微信工厂
public class WechatMessageFactory implements MessageFactory {
    @Override
    public Message createMessage() {
        return new WechatMessage();
    }
}

优化:反射+配置

如何使用反射优化工厂?

答案:

java
// 配置文件 factory.properties
product.A=com.example.ProductA
product.B=com.example.ProductB

// 工厂类
public class ReflectionFactory {
    private static Properties properties = new Properties();

    static {
        try {
            properties.load(ReflectionFactory.class.getClassLoader()
                .getResourceAsStream("factory.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Product createProduct(String type) {
        String className = properties.getProperty("product." + type);
        if (className == null) {
            throw new IllegalArgumentException("未知产品类型: " + type);
        }

        try {
            Class<?> clazz = Class.forName(className);
            return (Product) clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建产品失败", e);
        }
    }
}

优点

  • 新增产品只需修改配置文件
  • 无需修改代码

Spring中的工厂模式

BeanFactory?

答案:

Spring的BeanFactory就是工厂模式的典型应用。

java
// BeanFactory接口
public interface BeanFactory {
    Object getBean(String name);
    <T> T getBean(String name, Class<T> requiredType);
    <T> T getBean(Class<T> requiredType);
}

// 使用
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean(UserService.class);

Spring工厂的特点

  • 支持单例和原型模式
  • 支持依赖注入
  • 支持AOP
  • 支持生命周期管理

FactoryBean?

答案:

FactoryBean是Spring提供的工厂Bean接口。

java
public interface FactoryBean<T> {
    T getObject() throws Exception;  // 返回创建的对象
    Class<?> getObjectType();  // 返回对象类型
    boolean isSingleton();  // 是否单例
}

// 实现
@Component
public class UserFactoryBean implements FactoryBean<User> {

    @Override
    public User getObject() throws Exception {
        User user = new User();
        user.setName("张三");
        user.setAge(20);
        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

// 使用
@Autowired
private User user;  // 注入的是getObject()返回的对象

@Autowired
private UserFactoryBean userFactoryBean;  // 注入的是FactoryBean本身

应用场景

  • 创建复杂对象
  • 需要初始化配置的对象
  • 代理对象

实际案例

文件解析器工厂

答案:

java
// 解析器接口
public interface FileParser {
    void parse(String filePath);
}

// Excel解析器
public class ExcelParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析Excel文件: " + filePath);
    }
}

// CSV解析器
public class CsvParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析CSV文件: " + filePath);
    }
}

// JSON解析器
public class JsonParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析JSON文件: " + filePath);
    }
}

// 解析器工厂
public class FileParserFactory {
    public static FileParser createParser(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1);

        switch (extension.toLowerCase()) {
            case "xlsx":
            case "xls":
                return new ExcelParser();
            case "csv":
                return new CsvParser();
            case "json":
                return new JsonParser();
            default:
                throw new IllegalArgumentException("不支持的文件类型: " + extension);
        }
    }
}

// 使用
FileParser parser = FileParserFactory.createParser("data.xlsx");
parser.parse("data.xlsx");

HTTP客户端工厂

答案:

java
// HTTP客户端接口
public interface HttpClient {
    String get(String url);
    String post(String url, String body);
}

// OkHttp客户端
public class OkHttpClient implements HttpClient {
    @Override
    public String get(String url) {
        return "OkHttp GET: " + url;
    }

    @Override
    public String post(String url, String body) {
        return "OkHttp POST: " + url;
    }
}

// Apache HttpClient
public class ApacheHttpClient implements HttpClient {
    @Override
    public String get(String url) {
        return "Apache GET: " + url;
    }

    @Override
    public String post(String url, String body) {
        return "Apache POST: " + url;
    }
}

// 工厂
public class HttpClientFactory {
    private static final String CLIENT_TYPE = System.getProperty("http.client.type", "okhttp");

    public static HttpClient createClient() {
        switch (CLIENT_TYPE) {
            case "okhttp":
                return new OkHttpClient();
            case "apache":
                return new ApacheHttpClient();
            default:
                return new OkHttpClient();
        }
    }
}

// 使用
HttpClient client = HttpClientFactory.createClient();
String response = client.get("https://api.example.com/users");

对比总结

模式优点缺点适用场景
简单工厂实现简单违反开闭原则产品种类少且固定
工厂方法符合开闭原则类数量增加产品种类多且可扩展
抽象工厂产品族扩展方便产品等级扩展困难多个产品族

练习题

  1. 简单工厂和工厂方法的区别?
  2. 如何选择使用哪种工厂模式?
  3. Spring的BeanFactory和FactoryBean有什么区别?
  4. 工厂模式如何体现开闭原则?
  5. 如何使用工厂模式实现策略模式?

Released under the MIT License.