创建者模式:工厂方法模式

复制代码
生动讲解工厂方法模式

想象你要开一家"日志打印店":
1. 客户只需要说:"我要打印日志"
2. 不用关心是用打印机(文件日志)还是刻石碑(数据库日志)
3. 你根据订单类型自动选择对应的生产工具

这就是工厂方法模式的核心:**让子类决定创建什么对象**,客户端只需面向接口编程。

---

### 一、工厂方法模式四大核心组件

#### 1. 🧩 抽象产品(Logger接口)
```java
// 相当于"印刷品标准"
public interface Logger {
    void writeLog(); // 所有日志都必须支持打印功能
}
```

#### 2. 🖨️ 具体产品(FileLogger/DataBaseLogger)
```java
// 文件日志 - 相当于"纸质印刷"
public class FileLogger implements Logger {
    public void writeLog() {
        System.out.println("正在使用文件日志记录器记录日志");
    }
}

// 数据库日志 - 相当于"石碑雕刻"
public class DataBaseLogger implements Logger {
    public void writeLog() {
        System.out.println("正在使用数据库日志记录器记录日志");
    }
}
```

#### 3. 🏭 抽象工厂(LoggerFactory接口)
```java
// 印刷厂生产标准
public interface LoggerFactory {
    Logger createLogger(); // 所有工厂必须能生产日志产品
}
```

#### 4. 🔧 具体工厂(FileLoggerFactory/DataBaseLoggerFactory)
```java
// 文件日志工厂 - 专门生产纸质印刷品
public class FileLoggerFactory implements LoggerFactory {
    public Logger createLogger(){
        System.out.println("🖨️ 启动文件印刷流水线");
        return new FileLogger();
    }
}

// 数据库日志工厂 - 专门生产石碑雕刻
public class DataBaseLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        System.out.println("⛏️ 启动石碑雕刻工坊");
        return new DataBaseLogger();
    }
}
```

---

### 二、工作流程(客户下单场景)
```java
public class Client {
    public static void main(String[] args) {
        // 1. 获取工厂配置(客户选择印刷方式)
        LoggerFactory factory = XMLUtil.getBean();

        // 2. 创建日志产品(工厂生产)
        Logger logger = factory.createLogger();

        // 3. 使用产品(客户收货使用)
        logger.writeLog();
    }
}
```

#### 配置文件(订单需求单)
```xml
<!-- config.xml -->
<config>
    <!-- 切换此处即可更换日志类型 -->
    <className>创建者模式.工厂方法模式.具体工厂.FileLoggerFactory</className>
</config>
```

#### 配置解析器(订单处理中心)
```java
public class XMLUtil {
    public static LoggerFactory getBean() {
        // 1. 读取配置文件(接收订单)
        // 2. 解析XML获取类名(理解需求)
        String className = "创建者模式.工厂方法模式.具体工厂.FileLoggerFactory";

        // 3. 反射创建工厂(分配对应工厂)
        Class<?> clazz = Class.forName(className);
        return (LoggerFactory) clazz.newInstance();
    }
}
```

---

### 三、实际开发应用场景

#### 场景1:支付网关切换
```java
// 抽象产品
interface Payment {
    void pay(double amount);
}

// 具体产品
class Alipay implements Payment { /* 支付宝实现 */ }
class WechatPay implements Payment { /* 微信支付实现 */ }

// 抽象工厂
interface PaymentFactory {
    Payment create();
}

// 客户端
public class PaymentClient {
    public void processOrder(String paymentType) {
        PaymentFactory factory = PaymentConfig.getFactory(paymentType);
        Payment payment = factory.create();
        payment.pay(100.00);
    }
}
```

#### 场景2:跨数据库支持
```java
// 抽象产品
interface DatabaseConnection {
    void connect();
}

// 具体产品
class MySQLConnection implements DatabaseConnection { /* ... */ }
class OracleConnection implements DatabaseConnection { /* ... */ }

// 配置文件切换
<database>
    <type>MySQL</type>
    <!-- 或 <type>Oracle</type> -->
</database>
```

#### 场景3:多格式导出功能
```java
class ExportFactory {
    public static Exporter getExporter(String format) {
        switch(format) {
            case "PDF": return new PDFExporterFactory();
            case "EXCEL": return new ExcelExporterFactory();
            default: throw new IllegalArgumentException("不支持的格式");
        }
    }
}
```

---

### 四、六大核心优势

1. **解耦王者**:客户端只依赖抽象(Logger),不依赖具体实现
   ```mermaid
   graph LR
   Client-->|依赖|Logger
   Client-->|依赖|LoggerFactory
   LoggerFactory-->|生产|Logger
   ```

2. **开闭原则典范**:新增产品只需扩展,无需修改已有代码
   ```java
   // 新增云日志产品
   class CloudLogger implements Logger { /* ... */ }
   class CloudLoggerFactory implements LoggerFactory { /* ... */ }
   ```

3. **可配置性**:通过配置文件实现零代码修改切换实现
   ```xml
   <!-- 切换为云日志 -->
   <className>com.example.CloudLoggerFactory</className>
   ```

4. **职责清晰**:每个工厂只负责创建一种产品

5. **可测试性**:轻松Mock工厂进行单元测试

6. **可扩展性**:天然支持产品族扩展(结合抽象工厂模式)

---

### 五、五大避坑指南

1. **避免过度设计**
   ✅ 简单场景用简单工厂:
   ```java
   class LoggerFactory {
       public static Logger create(String type) {
           switch(type) {
               case "FILE": return new FileLogger();
               case "DB": return new DataBaseLogger();
           }
       }
   }
   ```
   ❌ 不要为只有1-2种实现的场景上完整工厂模式

2. **防止循环依赖**
   工厂不应依赖具体产品,应依赖抽象产品
   ```java
   // 正确示范 ✅
   class FileLoggerFactory implements LoggerFactory {
       public Logger createLogger() { // 返回接口
           return new FileLogger();
       }
   }
   ```

3. **性能考量**
   频繁创建对象时考虑对象池:
   ```java
   class DatabaseLoggerFactory {
       private static Queue<Logger> pool = new ConcurrentLinkedQueue<>();

       public Logger createLogger() {
           Logger logger = pool.poll();
           if(logger == null) {
               logger = new DatabaseLogger();
           }
           return logger;
       }
   }
   ```

4. **异常处理**
   工厂方法应明确处理创建失败:
   ```java
   public Logger createLogger() throws CreateException {
       try {
           return new DatabaseLogger();
       } catch (DBConnectionException e) {
           throw new CreateException("数据库连接失败", e);
       }
   }
   ```

5. **避免反射滥用**
   配置化创建时要防御非法类:
   ```java
   // XMLUtil改进
   if(!LoggerFactory.class.isAssignableFrom(clazz)) {
       throw new IllegalArgumentException("非法工厂类");
   }
   ```

---

### 六、三种演进形态

| 模式类型       | 适用场景                          | 示例                     |
|----------------|-----------------------------------|--------------------------|
| 简单工厂       | 产品类型固定且较少                | `LoggerFactory.create(type)` |
| **工厂方法**   | 需要灵活扩展产品                  | 本文示例                 |
| 抽象工厂       | 创建相关产品族(如不同主题UI组件)| `ThemeFactory.createButton()/createMenu()` |

---

### 七、最佳实践总结

1. **识别变化点**:将易变的创建逻辑封装进工厂
2. **面向接口编程**:客户端代码只与抽象产品/工厂交互
3. **配置化创建**:对频繁切换的实现使用配置文件+反射
4. **工厂命名规范**:使用`XXXFactory`统一后缀
5. **结合单例模式**:工厂本身通常实现为单例

```java
// 典型应用框架
DatabaseConnection conn = ConnectionFactory.getFactory(DatabaseType.MYSQL)
                                           .createConnection();
```

> 🌟 **黄金法则**:
> 当你的代码中出现`new`关键字时,问问自己:
> "这个对象的创建逻辑未来会变化吗?"
> 如果答案是肯定的,就该请出工厂方法模式了!

工厂方法就像制造业的"标准化生产线",让产品制造与使用分离。正确使用能让你的代码像乐高积木一样灵活组装,应对各种需求变化!
相关推荐
yujkss2 小时前
23种设计模式之【工厂方法模式】-核心原理与 Java实践
java·设计模式·工厂方法模式
allione2 小时前
Spring-AI简单实践
java·人工智能·spring
爱读源码的大都督3 小时前
2000字源码分析,聊聊Spring的扫描机制底层到底是如何实现的?
java·后端·spring
new_daimond3 小时前
设计模式-责任链模式详解
java·设计模式·责任链模式
维尔切3 小时前
Apache Tomcat 部署与配置
java·linux·运维·tomcat·apache
对不起初见i3 小时前
MyBatis-Plus 全方位深度指南:从入门到精通
java·数据库·mybatis
橙-极纪元3 小时前
windows系统使用sdkman管理java的jdk版本,WSL和Git Bash哪个更能方便管理jdk版本
java·windows·sdkman
再睡亿分钟!3 小时前
思考:客户端负载均衡和服务器负载均衡有什么区别?
java·开发语言·微服务·负载均衡
一个程序员(●—●)3 小时前
设计模式——结构型模式(下)
设计模式