设计模式——简单工厂模式(创建型)

摘要

本文主要介绍了简单工厂模式,包括其定义、结构、实现方式、适用场景、实战示例以及思考。简单工厂模式是一种创建型设计模式,通过工厂类根据参数决定创建哪一种产品类的实例,封装了对象创建的细节,使客户端无需关心具体类的创建逻辑。文章详细阐述了其角色组成、类图、时序图,探讨了两种常见的实现方式,分析了适合与不适合的场景,并提供了 Spring 项目和可插拔式策略工厂的实战示例。最后,还提出了支持 SPI 机制、注解标记策略名称和配置中心切换策略等思考方向。

1. 简单工厂模式定义

简单工厂模式 是一种创建型设计模式,它通过一个工厂类根据传入的参数决定创建哪一种产品类的实例

核心要点:

  • 核心角色:工厂类(Factory)
    • 负责创建产品对象。
    • 客户端只需传递参数,不关心具体类的创建逻辑。
  • 目标:封装对象创建的细节,将创建对象的逻辑从使用者中分离出来。

组成结构:

|-----------------|----------------------|
| 角色 | 说明 |
| Product | 抽象产品类(接口或抽象类) |
| ConcreteProduct | 具体产品类,实现 Product 接口 |
| Factory | 工厂类,包含创建产品对象的静态方法 |
| Client | 客户端,调用工厂方法获取产品对象并使用它 |

2. 简单工厂模式结构

2.1. 简单工厂类图

2.2. 简单工厂时序图

3. 简单工厂模式实现方式

实现方式主要分为两种:

|---------------|-------------------------------------|
| 实现方式 | 描述 |
| 1. 静态方法创建(常用) | 工厂方法是 static的,客户端直接通过类名调用,无需实例化工厂 |
| 2. 实例方法创建(灵活) | 工厂需要先实例化,再调用方法创建对象,适合支持不同配置或依赖注入 |

3.1. ✅ 实现方式 1:静态方法创建产品对象(最常见)

复制代码
// 抽象产品
public interface Product {
    void doWork();
}

// 具体产品 A
public class ProductA implements Product {
    public void doWork() {
        System.out.println("产品A正在工作");
    }
}

// 具体产品 B
public class ProductB implements Product {
    public void doWork() {
        System.out.println("产品B正在工作");
    }
}

// 简单工厂
public class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equalsIgnoreCase(type)) {
            return new ProductA();
        } else if ("B".equalsIgnoreCase(type)) {
            return new ProductB();
        }
        throw new IllegalArgumentException("不支持的产品类型:" + type);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Product product = SimpleFactory.createProduct("A");
        product.doWork();  // 输出:产品A正在工作
    }
}

3.2. ✅ 实现方式 2:使用工厂实例方法创建产品对象(便于配置)

复制代码
// 工厂类
public class SimpleFactory {
    
    public Product createProduct(String type) {
        if ("A".equalsIgnoreCase(type)) {
            return new ProductA();
        } else if ("B".equalsIgnoreCase(type)) {
            return new ProductB();
        }
        throw new IllegalArgumentException("不支持的产品类型:" + type);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        SimpleFactory factory = new SimpleFactory();
        Product product = factory.createProduct("B");
        product.doWork();  // 输出:产品B正在工作
    }
}

3.3. 🧠 简单工厂实现总结

|----------|----------|------------|
| 对比项 | 静态方法工厂 | 实例方法工厂 |
| 是否需要工厂对象 | 否 | 是 |
| 是否支持配置 | 较差 | 支持通过构造函数注入 |
| 使用场景 | 通用工厂、工具类 | 多配置或状态的工厂类 |

4. 简单工厂模式适合场景

4.1. ✅ 适合的场景(推荐使用简单工厂):

|----------------------------------|--------------------------------|
| 场景描述 | 原因 |
| 产品种类有限,变化不大 | 工厂中 if-else/switch 可维护性尚可,结构清晰 |
| 客户端不关心对象创建细节 | 封装了具体类的创建过程,减少耦合 |
| 多个子类实现一个接口/抽象类,客户端按条件选择创建哪一个 | 工厂根据传参决定具体返回哪个子类 |
| 代码结构相对简单,开发阶段处于初期 | 不想引入复杂设计,简单工厂最直观、易懂 |
| 希望集中管理对象创建 | 比 scattered new 更好维护和修改 |

📌 示例:日志输出、支付方式选择、消息发送器选择(短信/邮件/微信)等。

4.2. ❌ 不适合的场景(不推荐使用简单工厂):

|----------------------|---------------------------|
| 场景描述 | 问题 |
| 1. 产品种类经常变化或增加 | 每新增一个产品都要修改工厂类,违反"开放封闭原则" |
| 2. 产品种类太多,逻辑复杂 | 工厂类会膨胀成一个巨大类,不利于维护 |
| 3. 需要依赖注入、构造过程复杂 | 无法灵活注入依赖,缺乏拓展性 |
| 4. 对产品创建过程有定制要求 | 不能对不同产品的创建过程进行细粒度控制 |
| 5. 分布式、多模块开发场景 | 集中式工厂类会形成模块间强依赖,不利于解耦和部署 |

📌 示例:大型系统中涉及复杂对象生命周期控制的场景(如数据库连接池、线程池、配置驱动类等)。

4.3. ✅ 使用建议总结:

|-----------------------|-------------|
| 建议 | 原因 |
| ✔ 使用于产品稳定、变化少的小规模项目 | 简单、易维护 |
| ❌ 不建议用于大型、产品体系复杂的项目 | 违背开闭原则、扩展性差 |
| 👉 可结合工厂方法模式或抽象工厂模式演进 | 更好地支持扩展与解耦 |

5. 简单工厂模式实战示例

5.1. Spring项目中简单工厂示例

我们以"消息发送系统"为例,演示如何使用简单工厂根据输入创建不同的消息发送器(如短信、邮件、微信等)。

5.1.1. ✅ 场景目标

在 Spring 项目中,根据配置选择不同的消息发送器进行发送,如:

  • 配置为 sms:发送短信;
  • 配置为 email:发送邮件;
  • 配置为 wechat:发送微信。

5.1.2. ✅ 定义统一接口

复制代码
public interface MessageSender {
    void send(String message);
}

5.1.3. ✅ 三种发送器的实现类

复制代码
@Component("smsSender")
public class SmsSender implements MessageSender {
    public void send(String message) {
        System.out.println("发送短信:" + message);
    }
}

@Component("emailSender")
public class EmailSender implements MessageSender {
    public void send(String message) {
        System.out.println("发送邮件:" + message);
    }
}

@Component("wechatSender")
public class WechatSender implements MessageSender {
    public void send(String message) {
        System.out.println("发送微信:" + message);
    }
}

5.1.4. ✅ 简单工厂类(使用 Spring 容器管理)

复制代码
@Component
public class MessageSenderFactory {

    @Autowired
    private ApplicationContext applicationContext;

    public MessageSender createSender(String type) {
        switch (type.toLowerCase()) {
            case "sms":
                return applicationContext.getBean("smsSender", MessageSender.class);
            case "email":
                return applicationContext.getBean("emailSender", MessageSender.class);
            case "wechat":
                return applicationContext.getBean("wechatSender", MessageSender.class);
            default:
                throw new IllegalArgumentException("不支持的消息类型:" + type);
        }
    }
}

5.1.5. ✅ 使用示例(Controller 或 Service)

复制代码
@Service
public class NotifyService {

    @Autowired
    private MessageSenderFactory messageSenderFactory;

    // 模拟从配置文件或参数中读取类型
    @Value("${message.type:sms}")
    private String messageType;

    public void notifyUser(String content) {
        MessageSender sender = messageSenderFactory.createSender(messageType);
        sender.send(content);
    }
}

5.1.6. ✅ 应用入口(或 Controller)

复制代码
@RestController
public class MessageController {

    @Autowired
    private NotifyService notifyService;

    @GetMapping("/send")
    public String send(@RequestParam String msg) {
        notifyService.notifyUser(msg);
        return "消息已发送";
    }
}

5.1.7. ✅ application.yml 示例配置

复制代码
message:
  type: email

5.1.8. ✅ 简单工厂示例总结

|------|---------------------------------|
| 设计点 | 说明 |
| 工厂类 | MessageSenderFactory是核心简单工厂类 |
| 接口统一 | 所有发送器实现 MessageSender接口 |
| 解耦 | NotifyService不依赖具体实现类,依赖工厂和接口 |
| 可配置 | 支持通过配置控制行为,符合 Spring 项目实践 |

5.2. 可插拔式策略工厂(使用 SPI、Map 注册) 示例

下面是一个 可插拔式策略工厂(基于 Map 注册 + Spring 管理) 的完整示例,非常适用于需要动态切换、按配置扩展的业务策略类,比如:消息发送、支付渠道、风控策略、营销活动处理器等实现一种 灵活可扩展 的策略选择工厂,每个策略自动注册 到一个 Map<String, Strategy>中,不需要手动 switch-case

5.2.1. ✅ 定义统一接口(策略接口)

复制代码
public interface MessageSender {
    String type(); // 每个实现类提供自己的标识
    void send(String message);
}

5.2.2. ✅ 三种发送实现类(@Component 自动注入)

复制代码
@Component
public class SmsSender implements MessageSender {
    public String type() {
        return "sms";
    }

    public void send(String message) {
        System.out.println("【短信】发送:" + message);
    }
}

@Component
public class EmailSender implements MessageSender {
    public String type() {
        return "email";
    }

    public void send(String message) {
        System.out.println("【邮件】发送:" + message);
    }
}

@Component
public class WechatSender implements MessageSender {
    public String type() {
        return "wechat";
    }

    public void send(String message) {
        System.out.println("【微信】发送:" + message);
    }
}

5.2.3. ✅ 自动注册策略工厂(Map 注册方式)

复制代码
@Component
public class MessageSenderFactory {

    private final Map<String, MessageSender> senderMap = new HashMap<>();

    // Spring 会自动注入所有 MessageSender 的实现类
    @Autowired
    public MessageSenderFactory(List<MessageSender> senders) {
        for (MessageSender sender : senders) {
            senderMap.put(sender.type(), sender);
        }
    }

    public MessageSender getSender(String type) {
        MessageSender sender = senderMap.get(type);
        if (sender == null) {
            throw new IllegalArgumentException("不支持的消息类型: " + type);
        }
        return sender;
    }
}

5.2.4. ✅ 使用策略工厂的服务类

复制代码
@Service
public class NotifyService {

    @Autowired
    private MessageSenderFactory messageSenderFactory;

    public void notifyUser(String type, String content) {
        MessageSender sender = messageSenderFactory.getSender(type);
        sender.send(content);
    }
}

5.2.5. ✅ Controller 示例

复制代码
@RestController
@RequestMapping("/msg")
public class MessageController {

    @Autowired
    private NotifyService notifyService;

    @GetMapping("/send")
    public String send(@RequestParam String type, @RequestParam String msg) {
        notifyService.notifyUser(type, msg);
        return "消息已发送";
    }
}

5.2.6. ✅ 示例调用

请求:

复制代码
GET /msg/send?type=sms&msg=Hello_SMS
GET /msg/send?type=email&msg=Hello_Email
GET /msg/send?type=wechat&msg=Hello_WeChat

输出:

复制代码
【短信】发送:Hello_SMS
【邮件】发送:Hello_Email
【微信】发送:Hello_WeChat

5.2.7. 🚀 可插拔式策略工厂优势总结

|----------|-------------------------|
| 特性 | 说明 |
| 可插拔 | 新增一个实现类即可生效,无需改动工厂或业务代码 |
| 高扩展性 | 支持多策略、动态注册 |
| 易维护 | 摆脱 if-else / switch |
| Spring友好 | 利用 Spring 自动注入 & 生命周期 |

5.3. 🔌 简单工厂设计模式可拓展方向(高级)

  • 支持 SPI 机制(META-INF/services),用于插件式加载(可用于 jar 扩展、热插拔);
  • 支持 注解标记策略名称
  • 支持配置中心切换策略,如使用 @Value("${message.type}") 注入默认策略。

6. 简单工厂模式思考

6.1. 支持 SPI 机制(META-INF/services),用于插件式加载(可用于 jar 扩展、热插拔);

下面是一个完整的 基于 Java SPI(Service Provider Interface)机制的插件式策略工厂实现示例,它常用于实现模块解耦、可插拔、动态扩展功能。以"消息发送策略"为例,不使用 Spring 注解扫描,而是通过 SPI 机制动态加载所有实现类。

6.1.1. 🧩 定义 SPI 接口(策略接口)

复制代码
// src/main/java/com/example/spi/MessageSender.java
package com.example.spi;

public interface MessageSender {
    String type();             // 返回类型标识符
    void send(String message); // 发送消息逻辑
}

6.1.2. 📝 实现类(位于独立模块 / jar 中)

复制代码
// src/main/java/com/example/impl/SmsSender.java
package com.example.impl;

import com.example.spi.MessageSender;

public class SmsSender implements MessageSender {

    @Override
    public String type() {
        return "sms";
    }

    @Override
    public void send(String message) {
        System.out.println("【短信发送】" + message);
    }
}

6.1.3. 🗂️ 3SPI 注册文件

在 jar 包中的 resources/META-INF/services/ 路径下创建文件:

复制代码
META-INF/services/com.example.spi.MessageSender

内容如下(每一行一个实现类的全限定名):

复制代码
com.example.impl.SmsSender

✅ 当你有多个策略实现时,添加多行即可,如:

复制代码
com.example.impl.SmsSender
com.example.impl.EmailSender

6.1.4. ⚙️ 工厂类:动态加载所有策略实现

复制代码
package com.example.factory;

import com.example.spi.MessageSender;

import java.util.*;

public class MessageSenderFactory {

    private final Map<String, MessageSender> senderMap = new HashMap<>();

    public MessageSenderFactory() {
        // 加载spi接口所有接口实现类
        ServiceLoader<MessageSender> loader = ServiceLoader.load(MessageSender.class);
        for (MessageSender sender : loader) {
            senderMap.put(sender.type(), sender);
        }
    }

    public MessageSender getSender(String type) {
        MessageSender sender = senderMap.get(type);
        if (sender == null) {
            throw new IllegalArgumentException("不支持的消息类型: " + type);
        }
        return sender;
    }
}

ServiceLoader<MessageSender> loader = ServiceLoader.load(MessageSender.class);

Java 原生 SPI(Service Provider Interface)机制 的核心。它的底层原理其实并不复杂,是通过读取类路径下的 META-INF/services/ 目录下的文件,并利用反射机制加载实现类。以下是 ServiceLoader 的简化执行逻辑:

复制代码
// 从 META-INF/services/ 下查找接口对应的配置文件
Enumeration<URL> urls = classLoader.getResources("META-INF/services/" + serviceClass.getName());

// 读取文件中的类名
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String implClassName = reader.readLine();

// 通过反射实例化对象
Class<?> clazz = Class.forName(implClassName);
Object instance = clazz.newInstance();

每个实现类会被加载成一个对象,并返回一个延迟加载的迭代器。

6.1.5. 🧪 使用示例(main 方法中调用)

复制代码
public class Main {
    public static void main(String[] args) {
        MessageSenderFactory factory = new MessageSenderFactory();
        MessageSender sender = factory.getSender("sms");
        sender.send("Hello SPI!");
    }
}

6.1.6. 🎯 整体结构

复制代码
src/
├── main/
│   ├── java/
│   │   ├── com.example.spi/MessageSender.java
│   │   ├── com.example.impl/SmsSender.java
│   │   └── com.example.factory/MessageSenderFactory.java
│   └── resources/
│       └── META-INF/services/com.example.spi.MessageSender

6.1.7. 📌 SPI 模式的优点

|----------|-------------------------------------------------|
| 优点 | 说明 |
| 插件化、低耦合 | 实现类可来自外部 jar 包,主程序不需修改 |
| 动态扩展能力强 | 实现类可以热插拔(配合 OSGi、模块系统) |
| 框架内部广泛使用 | Dubbo、JDBC、Spring Boot 自动配置(spring.factories) |

6.1.8. 🚫 注意事项

  • SPI 默认是懒加载 + 非线程安全(如有并发需求请做好缓存);
  • IDE 无法提示类名(注册文件中填写错误 IDE 不会报警);
  • 多个 jar 中存在相同接口实现可能冲突;
  • 如果你使用的是 SpringBoot ,推荐改用 Spring 的 SPI(如 spring.factoriesspring.factoriesspring/org.springframework.boot.autoconfigure.EnableAutoConfiguration)机制配合。

6.2. 支持注解标记策略名称

策略模式 中,支持通过 注解 来标记每个策略的名称,可以极大提升策略类的可读性和扩展性,尤其适用于 SPI、Map 注册、Spring 容器注册等场景。

  • 多个 MessageSender 策略实现类
  • 每个类通过注解标记其类型名称(如 @MessageType("sms")
  • 使用 Map 注册所有策略,支持动态获取

6.2.1. ✅ 定义注解

复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageType {
    String value();  // 策略类型标识
}

6.2.2. ✅ 定义接口

复制代码
public interface MessageSender {
    void send(String message);
}

6.2.3. ✅ 实现策略类 + 注解标记

复制代码
@MessageType("sms")
public class SmsSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("发送短信: " + message);
    }
}

@MessageType("email")
public class EmailSender implements MessageSender {
    @Override
    public void send(String message) {
        System.out.println("发送邮件: " + message);
    }
}

6.2.4. ✅ 自动注册工厂类(注解扫描)

复制代码
public class MessageSenderFactory {

    private final Map<String, MessageSender> senderMap = new HashMap<>();

    public MessageSenderFactory() {
        // SPI 加载所有 MessageSender 实现类
        ServiceLoader<MessageSender> loader = ServiceLoader.load(MessageSender.class);
        for (MessageSender sender : loader) {
            MessageType annotation = sender.getClass().getAnnotation(MessageType.class);
            if (annotation != null) {
                senderMap.put(annotation.value(), sender);
            }
        }
    }

    public MessageSender getSender(String type) {
        MessageSender sender = senderMap.get(type);
        if (sender == null) {
            throw new IllegalArgumentException("不支持的消息类型: " + type);
        }
        return sender;
    }
}

6.2.5. ✅ 使用示例

复制代码
public class Main {
    public static void main(String[] args) {
        MessageSenderFactory factory = new MessageSenderFactory();
        factory.getSender("sms").send("验证码123456");
        factory.getSender("email").send("欢迎邮件");
    }
}

6.2.6. ✅ 优点

  • 注解直观标记类型,无需硬编码注册
  • 扩展一个新策略只需添加一个类并标注注解
  • ServiceLoader/Spring 配合使用,支持动态发现

6.3. 支持配置中心切换策略,如使用 @Value("${message.type}") 注入默认策略。

你希望实现一种 支持配置中心动态切换策略 的能力,例如通过配置中心的属性(如 Nacos、Apollo、Spring Cloud Config 等)控制当前策略的类型:实现思路(Spring + 注解 + Map 注册 + 配置驱动)

6.3.1. ✅ 定义策略注解

复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageType {
    String value();
}

6.3.2. ✅ 定义通用接口

复制代码
public interface MessageSender {
    void send(String message);
}

6.3.3. ✅ 多个策略实现类

复制代码
@Component
@MessageType("sms")
public class SmsSender implements MessageSender {
    public void send(String message) {
        System.out.println("发送短信: " + message);
    }
}

@Component
@MessageType("email")
public class EmailSender implements MessageSender {
    public void send(String message) {
        System.out.println("发送邮件: " + message);
    }
}

6.3.4. ✅ 策略工厂(Spring 容器自动注册 + 配置驱动)

复制代码
@Component
public class MessageSenderFactory implements InitializingBean {

    @Value("${message.type:email}")  // 默认email,可由配置中心动态更新
    private String defaultType;

    @Autowired
    private List<MessageSender> senderList;

    private final Map<String, MessageSender> senderMap = new HashMap<>();

    @Override
    public void afterPropertiesSet() {
        for (MessageSender sender : senderList) {
            MessageType annotation = sender.getClass().getAnnotation(MessageType.class);
            if (annotation != null) {
                senderMap.put(annotation.value(), sender);
            }
        }
    }
    /*
    * 如果使用默认方式,采用的就是nacos 配置策略
    */
    public MessageSender getSender() {
        MessageSender sender = senderMap.get(defaultType);
        if (sender == null) {
            throw new IllegalArgumentException("未找到对应的策略类型: " + defaultType);
        }
        return sender;
    }
    
    /*
    * 使用入参对应的策略
    */
    public MessageSender getSender(String type) {
        MessageSender sender = senderMap.get(type);
        if (sender == null) {
            throw new IllegalArgumentException("未找到对应的策略类型: " + type);
        }
        return sender;
    }
}

6.3.5. ✅ 使用示例

复制代码
@RestController
public class MessageController {

    @Autowired
    private MessageSenderFactory factory;

    /*
    * 如果使用默认方式,采用的就是nacos配置策略
    */
    @GetMapping("/send")
    public String send(@RequestParam String msg) {
        factory.getSender().send(msg);
        return "消息已发送";
    }

    /*
    * 如果使用入参对应方式发送
    */
    @GetMapping("/email/send")
    public String send(@RequestParam String sendType, @RequestParam String msg) {
        factory.getSender(sendType).send(msg);
        return "消息已发送";
    }
}

6.3.6. ✅ 配置变更如何生效(支持热刷新)?

如果你使用配置中心(如 Nacos),你还可以让 @Value("${message.type}") 自动刷新:

复制代码
@RefreshScope
@Component
public class MessageSenderFactory implements InitializingBean {
    ...
}

这样,在 Nacos 修改 message.type=emailsms,会实时切换策略。

6.3.7. ✅ 总结优势

|----------|-----------------------------|
| 特性 | 实现方式 |
| 策略标识 | 注解 @MessageType |
| 扫描所有策略实现 | Spring 注入 List<> |
| 配置驱动选择策略 | @Value("${message.type}") |
| 动态刷新策略选择 | @RefreshScope+ Nacos |

6.4. 使用SPI 机制(META-INF/services),用于插件式加载(可用于 jar 扩展、热插拔);与普通简单工厂方法实现区别?

使用 SPI 机制( META-INF/services**)** 和 普通简单工厂模式 都是实现"根据类型返回不同实现类"的策略工厂思想,但它们在实现机制、应用场景和扩展性上有很大不同。以下是详细对比和说明:

6.4.1. 🔍 核心区别对比表

|---------------------|--------------------------------|-----------------------------|
| 项目 | SPI机制(ServiceLoader) | 简单工厂模式(自己注册/Map) |
| 加载方式 | JDK 内置 ServiceLoader 自动发现实现类 | 自己手动注册,或用注解 + Spring 扫描 |
| 实现类注册位置 | META-INF/services/接口全类名 | 代码中通过 Map<String, Object> |
| 是否依赖容器(如Spring) | 否(纯 JDK 原生机制) | 是(通常依赖 Spring 注入、配置) |
| 扩展性(插件支持) | 强,可动态加入 jar 包扩展实现 | 弱,必须修改代码或重启注册逻辑 |
| 热插拔能力 | 支持(添加 jar 即生效,重启可用) | 不支持,必须重启或改代码 |
| 类型标识方式 | 实现类自己定义类型(如 type()方法) | 通常用注解或手动 put(key, impl) |
| 适合插件机制 | ✅ 非常适合 | ❌ 不适合 |
| 使用门槛 | 中(需要手动写 SPI 配置文件) | 低(代码中实现注册) |

6.4.2. 🧩 SPI机制(JDK ServiceLoader)工作原理

  • 你要做的:
    1. 定义一个接口,比如:MessageSender
    2. 实现多个类,比如:EmailSenderSmsSender 并实现该接口
    3. resources/META-INF/services/com.example.spi.MessageSender 文件中列出所有实现类的 全限定类名

    com.example.sender.EmailSender
    com.example.sender.SmsSender

  • 运行时使用 ServiceLoader 自动扫描并实例化:

    ServiceLoader<MessageSender> loader = ServiceLoader.load(MessageSender.class);
    for (MessageSender sender : loader) {
    senderMap.put(sender.type(), sender);
    }

📦 实现类可以是外部 jar 包,插件式部署。无需改主程序代码。

6.4.3. 🛠️ 简单工厂模式实现方式

实现逻辑通常在代码里"硬编码"注册每种类型与实现类的关系:

复制代码
public class SenderFactory {
    private static final Map<String, MessageSender> map = new HashMap<>();

    static {
        map.put("email", new EmailSender());
        map.put("sms", new SmsSender());
    }

    public static MessageSender getSender(String type) {
        return map.get(type);
    }
}

🧱 实现类和工厂强耦合,新增类型时,必须改代码、重编、重新部署。

6.4.4. 🚦 使用场景对比

|--------------------|--------------------|
| 场景 | 建议使用方式 |
| 插件式架构,第三方扩展点 | ✅ 使用 SPI |
| 配置中心控制策略选择 | ✅ 使用 Spring + Map |
| 内部服务、类型少且固定 | ✅ 简单工厂 |
| 支持 jar 级别热插拔、可拔插插件 | ✅ SPI + jar 模块化 |
| 多环境配置动态选择实现 | ✅ Spring 结合 @Value |

7. 博文参考

相关推荐
kingmax542120081 小时前
【洛谷P9303题解】AC- [CCC 2023 J5] CCC Word Hunt
数据结构·c++·算法·广度优先
fanged2 小时前
构建系统maven
java·maven
沙滩小岛小木屋2 小时前
maven编译时跳过test过程
java·maven
白熊1882 小时前
【机器学习基础】机器学习入门核心算法:XGBoost 和 LightGBM
人工智能·算法·机器学习
bai_lan_ya2 小时前
数据结构-排序-排序的七种算法(2)
数据结构·算法·排序算法
江沉晚呤时3 小时前
SQL Server 事务详解:概念、特性、隔离级别与实践
java·数据库·oracle·c#·.netcore
还是鼠鼠3 小时前
单元测试-概述&入门
java·开发语言·后端·单元测试·log4j·maven
Li-Yongjun3 小时前
5G-A:开启通信与行业变革的新时代
运维·服务器·5g
全域智图4 小时前
元胞自动机(Cellular Automata, CA)
人工智能·算法·机器学习
珂朵莉MM4 小时前
2022 RoboCom 世界机器人开发者大赛-本科组(省赛)解题报告 | 珂学家
人工智能·算法·职场和发展·深度优先·图论