🧠 一、设计模式全景图(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-else
或switch-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 是什么”,不关心策略内部细节
📘 结语 & 推荐背诵顺序:
面试答题推荐先背:
策略、单例、责任链、代理、工厂、模板方法、观察者
如果你说得出“项目用过 + 结构 + 代码 + 类比”,基本是面试加分项 ✅