面试官:你在项目里使用过工厂模式吗?

面试官:你在项目里使用过工厂模式吗?
你:使用过,我记得Spring就是使用的工厂模式,工厂模式是……。
面试官:……嗯,说的对,但我问的是你项目里使没使用过,不是框架里。
你:啊额,不好意思,没使用过。
面试官:那行,你回去等通知吧!
你:哇呜呜

🌿 一、场景描述

系统中需要支持多种消息发送方式:

  • 短信
  • 邮件
  • 微信(假设后续新增)

如果不使用设计模式,最直觉的方式是:

if (type.equals("email")) {
    // 发送邮件逻辑
} else if (type.equals("sms")) {
    // 发送短信逻辑
}

⚠️ 缺点

  • 每新增一种消息,都要修改 if/else,违反开闭原则(对扩展开放,对修改关闭)。
  • 耦合严重,代码难以维护、测试、扩展。

🌸 二、工厂模式优雅解决

核心思想: 将消息发送逻辑进行抽象,不同消息发送器实现同一个接口,通过工厂创建对应发送器,屏蔽具体实现细节。


1. 定义消息发送器接口(顶层标准)

public interface MessageSender {
    void sendMessage(String message);
}

2. 实现不同消息发送器(多种实现方式)

// 短信发送器
public class SmsSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        System.out.println("发送短信: " + message);
        // 实际调用短信服务API
    }
}

// 邮件发送器
public class EmailSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        System.out.println("发送邮件: " + message);
        // 实际调用邮件服务API
    }
}

3. 创建消息发送器工厂(统一创建对象)

public class MessageSenderFactory {
    public static MessageSender getSender(String type) {
        if ("sms".equalsIgnoreCase(type)) {
            return new SmsSender();
        } else if ("email".equalsIgnoreCase(type)) {
            return new EmailSender();
        } else {
            throw new IllegalArgumentException("不支持的消息类型: " + type);
        }
    }
}

4. 调用示例(对外统一)

public class Main {
    public static void main(String[] args) {
        MessageSender smsSender = MessageSenderFactory.getSender("sms");
        smsSender.sendMessage("您的验证码是 1234");

        MessageSender emailSender = MessageSenderFactory.getSender("email");
        emailSender.sendMessage("欢迎注册我们的网站!");
    }
}

🌲 三、如果新增一种“微信消息”怎么办?

无需修改现有逻辑,只需:

  1. 实现一个新的 WeChatSender 类。
  2. MessageSenderFactory 中新增分支,或者使用更优雅的注册方式(后面扩展讲)。
public class WeChatSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        System.out.println("发送微信: " + message);
    }
}

🌟 四、更优雅的优化(去掉 if/else,改成 Map 注册)

为了避免 MessageSenderFactory 里 if/else 越来越长,可以用 Map 注册管理:

public class MessageSenderFactory {
    private static final Map<String, MessageSender> senderMap = new HashMap<>();

    static {
        senderMap.put("sms", new SmsSender());
        senderMap.put("email", new EmailSender());
        senderMap.put("wechat", new WeChatSender()); // 新增
    }

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

优点

  • 解耦扩展,新增一种类型只需要注册即可,无需修改其他代码
  • 统一接口调用,方便测试、维护。

💡 五、总结:工厂模式解决的问题

问题工厂模式的解决方式
创建对象逻辑复杂把对象创建交给工厂,调用方不用管细节
新增消息发送方式需要修改大量代码只需新增实现类,工厂注册即可,扩展方便
调用方与实现类耦合严重通过接口+工厂解耦,调用方只依赖接口
代码冗长难维护工厂集中管理创建,易于维护

🚀 六、现实项目中如何落地?

  1. 抽象接口(如消息发送器标准、支付方式标准等)。
  2. 具体实现(不同消息类型、不同支付方式)。
  3. 工厂模式管理创建,配合 Spring 容器、Bean 工厂可以自动注入管理。
  4. 使用场景
    • 消息发送(短信、邮件、微信、站内信)。
    • 支付(微信、支付宝、银行卡等)。
    • 文件存储(本地、阿里OSS、腾讯COS等)。
    • 日志收集器(本地文件、数据库、ES等)。

🌿 七、问题引入:传统工厂模式的问题

在刚才的 Map 注册方式 中,你有没有发现:

static {
    senderMap.put("sms", new SmsSender());
    senderMap.put("email", new EmailSender());
    senderMap.put("wechat", new WeChatSender()); // 新增
}

🔴 缺点

  • 每次新增一种发送器,还得 手动在静态块中注册
  • 如果发送器越来越多,管理成本高,不符合开闭原则。

那么有没有更好的办法?当然有!


🌸 八、结合 Spring 容器自动管理 —— 实现动态扩展

我们把消息发送器的实现类,交给 Spring 管理,并动态识别和注册。

⭐ 核心目标:

  1. 新增实现类不动工厂逻辑,自动识别和注册。
  2. 灵活切换消息发送方式。
  3. 和工厂结合,屏蔽具体实现细节。

🌲 九、实现步骤

1. 定义统一接口(抽象标准)

public interface MessageSender {
    void sendMessage(String message);
    String getType(); // 新增方法,返回具体类型,如 "sms"、"email"
}

getType 用来标识发送器的类型,供工厂自动识别。


2. 实现不同发送器(自动交给Spring管理)

@Component
public class SmsSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        System.out.println("发送短信: " + message);
    }

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

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

    @Override
    public String getType() {
        return "email";
    }
}

🌟 注意:加上 @Component 注解,自动注册为 Spring Bean。


3. 工厂类,自动注入所有实现(动态注册)

@Component
public class MessageSenderFactory {

    // Spring 会自动注入所有实现 MessageSender 接口的 Bean
    private final Map<String, MessageSender> senderMap = new HashMap<>();

    @Autowired
    public MessageSenderFactory(List<MessageSender> messageSenders) {
        for (MessageSender sender : messageSenders) {
            senderMap.put(sender.getType(), sender); // 动态注册
        }
    }

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

亮点

  • 自动扫描所有实现,无需手动注册
  • 每个实现类自行返回 type,动态识别。
  • 轻松扩展,新加微信发送器,仅需新增实现类,无需修改工厂!

4. 使用示例(Controller 或 Service 中调用)

@RestController
@RequestMapping("/message")
public class MessageController {

    @Autowired
    private MessageSenderFactory factory;

    @PostMapping("/send")
    public String send(@RequestParam String type, @RequestParam String content) {
        MessageSender sender = factory.getSender(type);
        sender.sendMessage(content);
        return "消息已发送";
    }
}

🔥 动态选择发送器

POST /message/send?type=sms&content=你好
POST /message/send?type=email&content=Hello Email

✨ 十、效果总结

问题传统工厂模式Spring 结合改进后
新增消息类型需要修改工厂注册逻辑仅新增实现类,自动识别
耦合度
扩展性较差极强
管理成本高,容易遗漏低,自动托管

🌻 十一、如果继续新增新消息器如微信?

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

    @Override
    public String getType() {
        return "wechat";
    }
}

✅ 工厂不需要动一行代码!系统自动支持 wechat 类型。


🌟 十二、总结一句话

工厂模式 + 策略模式 + Spring IOC 自动托管

实现了一个 高扩展性、低耦合、易维护 的消息发送器体系,符合真正的企业级项目开发标准!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值