项目中使用到的设计模式有哪些?都应用在什么场景?策略模式的缺点是什么?

🧠 一、设计模式全景图(23种经典分类)

类型设计模式类比记忆
创建型单例、工厂方法、抽象工厂、建造者、原型创建对象的“套路”
结构型适配器、桥接、装饰器、组合、外观、享元、代理组装结构的“桥梁”
行为型模板方法、策略、责任链、观察者、状态、命令、访问者、解释器、备忘录、中介者、迭代器行为流程的“套路”


🔥 二、面试重点 + 应用场景 + 类比 + 代码示例(精选)


✅ 1. 策略模式(Strategy Pattern)

  • 关键词:动态切换行为、替代 if-else

  • 项目场景:支付方式选择、优惠计算、认证方式

  • 生活比喻:超市收银台选择不同支付方式(微信/支付宝/现金)

🧩 示例代码:
public interface PayStrategy {
    void pay(int amount);
}

public class WeChatPay implements PayStrategy {
    public void pay(int amount) {
        System.out.println("微信支付:" + amount);
    }
}

public class AliPay implements PayStrategy {
    public void pay(int amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

public class PayContext {
    private PayStrategy strategy;
    public PayContext(PayStrategy strategy) { this.strategy = strategy; }
    public void execute(int amount) { strategy.pay(amount); }
}


//使用示例
public class Main {
    public static void main(String[] args) {
        int amount = 500;

        // 选择策略:微信支付
        PayContext context1 = new PayContext(new WeChatPay());
        context1.execute(amount); // 输出:微信支付:500

        // 切换策略:支付宝
        PayContext context2 = new PayContext(new AliPay());
        context2.execute(amount); // 输出:支付宝支付:500
    }
}


✅ 2. 单例模式(Singleton Pattern)

  • 关键词:全局唯一、懒汉/饿汉、线程安全

  • 项目场景:配置类、工具类、线程池、数据库连接池

  • 生活比喻:操作系统中的“打印队列管理器”,全局唯一

🧩 懒汉线程安全写法:
public class ConfigManager {
    private static volatile ConfigManager instance;

    private ConfigManager() {}

    public static ConfigManager getInstance() {
        if (instance == null) {
            synchronized (ConfigManager.class) {
                if (instance == null) instance = new ConfigManager();
            }
        }
        return instance;
    }
}


✅ 3. 工厂模式(Factory Pattern)

  • 关键词:创建对象、解耦构造逻辑

  • 项目场景:消息发送服务、支付通道选择、对象初始化

  • 生活比喻:汽车工厂生产不同品牌车型

🧩 示例代码:
public interface Sender {
    void send(String msg);
}

public class SmsSender implements Sender {
    public void send(String msg) {
        System.out.println("发送短信:" + msg);
    }
}

public class SenderFactory {
    public static Sender create(String type) {
        return "sms".equals(type) ? new SmsSender() : null;
    }
}


✅ 4. 责任链模式(Chain of Responsibility)

  • 关键词:多条件处理、可中断链、组合

  • 项目场景:订单校验链、请求过滤器链、审批流程

  • 生活比喻:传送带,每个工人处理一项,如果满足条件继续传

🧩 示例代码:

abstract class Handler {
    protected Handler next;
    public Handler setNext(Handler next) {
        this.next = next; return next;
    }
    public void handle(String req) {
        if (check(req) && next != null) next.handle(req);
    }
    protected abstract boolean check(String req);
}

class LoginCheck extends Handler {
    protected boolean check(String req) {
        System.out.println("校验登录用户:" + req);
        return !req.isEmpty();
    }
}


✅ 5. 代理模式(Proxy Pattern)

  • 关键词:增强、AOP、控制访问、缓存

  • 项目场景:接口限流、权限校验、缓存代理、RPC远程调用

  • 生活比喻:翻译是发言者的代理

🧩 示例代码:

public interface Service {
    void request();
}

public class RealService implements Service {
    public void request() {
        System.out.println("处理真实请求");
    }
}

public class ServiceProxy implements Service {
    private final Service target;
    public ServiceProxy(Service target) { this.target = target; }

    public void request() {
        System.out.println("检查权限");
        target.request();
        System.out.println("记录日志");
    }
}


✅ 6. 模板方法模式(Template Method)

  • 关键词:固定流程、子类实现、流程复用

  • 项目场景:报表导出、通用调度、批处理

  • 生活比喻:做饭的流程固定,炒菜内容不同

🧩 示例代码:
abstract class TaskTemplate {
    public final void execute() {
        prepare(); doTask(); finish();
    }
    protected void prepare() { System.out.println("准备资源"); }
    protected abstract void doTask();
    protected void finish() { System.out.println("清理资源"); }
}

class DataExportTask extends TaskTemplate {
    protected void doTask() { System.out.println("导出数据"); }
}


✅ 7. 观察者模式(Observer Pattern)

  • 关键词:一对多依赖、发布订阅

  • 项目场景:事件通知、MQ监听、Spring事件模型

  • 生活比喻:老师通知多个学生成绩

🧩 示例代码:
interface Observer {
    void update(String msg);
}

class EmailClient implements Observer {
    public void update(String msg) {
        System.out.println("收到通知邮件:" + msg);
    }
}

class EventBus {
    private final List<Observer> observers = new ArrayList<>();
    public void register(Observer o) { observers.add(o); }
    public void publish(String msg) {
        observers.forEach(o -> o.update(msg));
    }
}


🎯 三、设计模式应用分类脑图(结构记忆)


创建型:
    - 单例:唯一对象(配置/池)
    - 工厂:对象创建抽象
    - 建造者:复杂对象逐步构建(如 StringBuilder)
结构型:
    - 代理:控制访问 + 增强(如 AOP)
    - 适配器:接口适配(如 InputStreamReader)
    - 装饰器:功能增强(如 IO流链)
行为型:
    - 策略:动态选择行为(促销)
    - 责任链:多个处理节点组合(校验链)
    - 模板方法:固定流程(数据导出)
    - 观察者:事件订阅(MQ通知)

❌ 四、策略模式的主要缺点

1. 客户端必须了解所有策略类

  • 客户端需要知道有哪些策略,以及如何选择合适的策略。

  • 一旦策略种类太多,管理和选择会变得复杂。

📌 举例说明:
在一个优惠计算系统中,如果有满减、折扣、积分抵扣、秒杀、拼团等策略,使用者必须知道每种策略的用途和名称才能正确调用。


2. 策略类数量可能激增(类爆炸)

  • 每个策略都要一个类,策略多时容易导致类文件数量庞大,维护成本上升。

📌 项目举例:
某金融系统支持几十种利率计算策略,每种都拆成类,光是策略包就有上百个文件,维护困难。


3. 无法避免策略类之间的代码重复

  • 某些策略之间逻辑类似,但由于设计解耦为不同类,可能会造成重复代码。

📌 解决方法:可以使用抽象基类或模板方法模式来复用通用逻辑。


4. 策略选择逻辑仍可能存在 if-else(分发中心)

  • 如果没有结合工厂模式或注册中心来管理策略实例,调用时往往还是得写一堆 if-elseswitch-case 来选择策略。

📌 示例优化:
结合 Spring 容器 + 注解注册 + 策略工厂可自动管理,不需要写 if-else,提升扩展性。


✅ 实际建议

  • 策略类太多 → 可以做分组 + 工厂管理 + 接口注册

  • 代码复用低 → 使用抽象基类或模板方法结合

  • 策略无法动态扩展 → 可用配置 + 反射动态加载策略类

5、改造示例:上面策略模式改进后写法:工厂 + 策略模式(含 Map 路由)

🧱 Step 1:定义支付策略接口及实现类
public interface PayStrategy {
    void pay(int amount);
}

public class WeChatPay implements PayStrategy {
    public void pay(int amount) {
        System.out.println("微信支付:" + amount);
    }
}

public class AliPay implements PayStrategy {
    public void pay(int amount) {
        System.out.println("支付宝支付:" + amount);
    }
}


🏭 Step 2:创建策略工厂,内部用 Map<String, PayStrategy> 路由

public class PayStrategyFactory {
    private static final Map<String, PayStrategy> STRATEGY_MAP = new HashMap<>();

    static {
        STRATEGY_MAP.put("wechat", new WeChatPay());
        STRATEGY_MAP.put("alipay", new AliPay());
    }

    public static PayStrategy getStrategy(String payType) {
        PayStrategy strategy = STRATEGY_MAP.get(payType.toLowerCase());
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式: " + payType);
        }
        return strategy;
    }
}


🚀 Step 3:调用方式(上下文类可选,也可直接用工厂)
public class Main {
    public static void main(String[] args) {
        int amount = 888;

        // 假设来自用户选择的支付方式
        String payType = "wechat";

        PayStrategy strategy = PayStrategyFactory.getStrategy(payType);
        strategy.pay(amount); // 输出:微信支付:888
    }
}


📌 实际效果
  • 没有 if-else / switch

  • 扩展支付方式时,只需添加新的策略类 + 注册到 map

  • 对外调用时,只关心“我传的 payType 是什么”,不关心策略内部细节


📘 结语 & 推荐背诵顺序:

面试答题推荐先背:

策略、单例、责任链、代理、工厂、模板方法、观察者

如果你说得出“项目用过 + 结构 + 代码 + 类比”,基本是面试加分项 ✅

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值