乐于分享
好东西不私藏

【Java专题33】设计模式实战:从源码到架构的23种模式应用

【Java专题33】设计模式实战:从源码到架构的23种模式应用

面试场景还原

面试官:“你在项目中用过哪些设计模式?工厂模式和策略模式有什么区别?Spring中用了哪些设计模式?你能现场写一个线程安全的单例吗?装饰器模式和代理模式的区别是什么?”

:(脑海中浮现出23种模式的全景图,从创建型到行为型,从源码到应用场景逐层展开…)

考察重点

这道题是中高级工程师的核心题,面试官想考察:

  1. 模式理解:能否准确说出常用设计模式的意图、结构和适用场景

  2. 源码识别:能否在常用框架(Spring、MyBatis、JDK)中识别设计模式的应用

  3. 实战能力:能否根据业务场景选择合适的模式,并给出实现

  4. 架构思维:能否在系统设计中灵活组合设计模式解决问题

一、设计模式全景图

┌─────────────────────────────────────────────────────────────────┐│                    设计模式分类                                  │├─────────────────────────────────────────────────────────────────┤│                                                                  ││  创建型(Creational)—— 对象创建                                 ││  ├── 单例(Singleton):全局唯一实例                            ││  ├── 工厂方法(Factory Method):延迟实例化到子类               ││  ├── 抽象工厂(Abstract Factory):产品族创建                   ││  ├── 建造者(Builder):复杂对象分步构建                        ││  └── 原型(Prototype):克隆创建                                ││                                                                  ││  结构型(Structural)—— 类/对象组合                             ││  ├── 代理(Proxy):控制访问                                    ││  ├── 适配器(Adapter):接口转换                                ││  ├── 装饰器(Decorator):动态增强功能                          ││  ├── 组合(Composite):树形结构                                ││  ├── 外观(Facade):简化接口                                   ││  ├── 桥接(Bridge):抽象与实现分离                             ││  └── 享元(Flyweight):共享对象                                ││                                                                  ││  行为型(Behavioral)—— 算法与职责分配                         ││  ├── 策略(Strategy):算法族可互换                            ││  ├── 模板方法(Template Method):骨架固定,步骤可定制           ││  ├── 观察者(Observer):事件通知                               ││  ├── 责任链(Chain of Responsibility):请求传递                ││  ├── 状态(State):状态驱动行为                               ││  ├── 命令(Command):请求封装                                 ││  ├── 迭代器(Iterator):遍历集合                              ││  └── 访问者(Visitor):操作分离                               ││                                                                  │└─────────────────────────────────────────────────────────────────┘

二、创建型模式实战

2.1 单例模式(Singleton)

形象比喻:一个国家只有一个总统。无论你在哪里问“谁是总统”,都是同一个人。

线程安全的双重检查锁实现

public class Singleton {    // volatile防止指令重排序    private static volatile Singleton instance;    privateSingleton() {        // 防止反射入侵        if (instance != null) {            throw new RuntimeException("请使用getInstance()方法");        }    }    publicstatic Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new Singleton();                }            }        }        return instance;    }}
枚举单例(最安全) :
public enum SingletonEnum {    INSTANCE;    publicvoiddoSomething() {        System.out.println("枚举单例执行");    }}

Spring中的应用:Spring容器中的Bean默认就是单例(@Scope("singleton"))。

2.2 工厂模式(Factory Method & Abstract Factory)

形象比喻:工厂模式就像一家汽车工厂。你告诉工厂需要“轿车”,它生产轿车;需要“SUV”,它生产SUV。你不用关心具体是怎么造的。

简单工厂(非GoF) :

public class PaymentFactory {    public static Payment createPayment(Stringtype) {        switch (type) {            case "alipay"return new Alipay();            case "wechat"return new WechatPay();            case "credit"return new CreditCardPay();            defaultthrow new IllegalArgumentException("未知支付类型");        }    }}
工厂方法
// 产品接口public interface Payment {    void pay(BigDecimal amount);}// 具体产品public class Alipay implements Payment {    @Override    public void pay(BigDecimal amount) {        System.out.println("支付宝支付:" + amount);    }}// 工厂接口public interface PaymentFactory {    Payment createPayment();}// 具体工厂public class AlipayFactory implements PaymentFactory {    @Override    public Payment createPayment() {        return new Alipay();    }}

Spring中的应用

  • BeanFactory:工厂模式,根据bean名称/类型创建Bean实例

  • FactoryBean:更灵活的自定义工厂

2.3 建造者模式(Builder)

形象比喻:建造者模式就像组装一台电脑。你可以选择CPU、内存、硬盘等组件,最终组装成一台完整的电脑。

@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Order {    private Long id;    private String orderNo;    private Long userId;    private BigDecimal amount;    private String address;    private List<OrderItem> items;}// 使用Lombok @Builder,或手动实现Order order = Order.builder()    .orderNo("ORD2024001")    .userId(123L)    .amount(BigDecimal.valueOf(99.99))    .address("北京市朝阳区")    .build();

三、结构型模式实战

3.1 代理模式(Proxy)

形象比喻:明星的经纪人。你想请明星演出,不直接联系明星,而是联系经纪人。经纪人帮你处理合同、档期、费用等事务。

静态代理

public interface OrderService {    void createOrder(Order order);}public class OrderServiceImpl implements OrderService {    @Override    public void createOrder(Order order) {        System.out.println("创建订单:" + order.getOrderNo());    }}// 静态代理(增强日志)public class OrderServiceProxy implements OrderService {    private final OrderService target;    public OrderServiceProxy(OrderService target) {        this.target = target;    }    @Override    public void createOrder(Order order) {        System.out.println("开始创建订单,时间:" + System.currentTimeMillis());        target.createOrder(order);        System.out.println("订单创建完成");    }}
动态代理(JDK Proxy) :
public class LogProxyHandler implements InvocationHandler {    private final Object target;    public LogProxyHandler(Object target) {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("【JDK动态代理】前置通知:" + method.getName());        Object result = method.invoke(target, args);        System.out.println("【JDK动态代理】后置通知");        return result;    }    public static <T> T createProxy(T target) {        return (T) Proxy.newProxyInstance(            target.getClass().getClassLoader(),            target.getClass().getInterfaces(),            new LogProxyHandler(target)        );    }}
CGLIB动态代理(无接口) :
public classCglibInterceptorimplementsMethodInterceptor{    @Override    public Object intercept(Object obj, Method methodObject[] argsMethodProxyproxythrowsThrowable{        System.out.println("【CGLIB】前置通知");        Object result = proxy.invokeSuper(obj, args);        System.out.println("【CGLIB】后置通知");        return result;    }}OrderService service = (OrderService) Enhancer.create(OrderService.class, new CglibInterceptor());

Spring中的应用

  • AOP:JDK动态代理(有接口)或CGLIB(无接口)

  • 事务管理@Transactional注解通过代理实现

3.2 装饰器模式(Decorator)

形象比喻:咖啡店的点单。你可以点一杯咖啡,然后加糖、加奶、加巧克力。每个装饰器都会给咖啡增加新功能,但它们还是咖啡。

// 组件接口public interface Coffee {    String getDescription();    double getCost();}// 具体组件public class SimpleCoffee implements Coffee {    @Override    public String getDescription() { return "简单咖啡"; }    @Override    public double getCost() { return 5.0; }}// 抽象装饰器public abstract class CoffeeDecorator implements Coffee {    protected Coffee decoratedCoffee;    public CoffeeDecorator(Coffee coffee) {        this.decoratedCoffee = coffee;    }}// 具体装饰器:加奶public class MilkDecorator extends CoffeeDecorator {    public MilkDecorator(Coffee coffee) { super(coffee); }    @Override    public String getDescription() {        return decoratedCoffee.getDescription() + " + 奶";    }    @Override    public double getCost() {        return decoratedCoffee.getCost() + 1.5;    }}

代理 vs 装饰器

模式
目的
关系
典型场景
代理
控制访问、增强非业务功能
代理类与目标类实现同一接口
AOP、远程调用
装饰器
动态添加新功能
装饰器持有被装饰对象引用
Java IO流

Java IO中的应用BufferedInputStream装饰FileInputStream,增加缓冲功能。

四、行为型模式实战

4.1 策略模式(Strategy)

形象比喻:出行方式选择。去机场可以打车、坐地铁、骑自行车。每种方式都是一个策略,你可以根据需要随时切换。

// 策略接口public interface PaymentStrategy {    void pay(BigDecimal amount);}// 具体策略:支付宝public class AlipayStrategy implements PaymentStrategy {    @Override    public void pay(BigDecimal amount) {        System.out.println("使用支付宝支付:" + amount);    }}// 具体策略:微信public class WechatPayStrategy implements PaymentStrategy {    @Override    public void pay(BigDecimal amount) {        System.out.println("使用微信支付:" + amount);    }}// 上下文public class PaymentContext {    private PaymentStrategy strategy;    public PaymentContext(PaymentStrategy strategy) {        this.strategy = strategy;    }    public void setStrategy(PaymentStrategy strategy) {        this.strategy = strategy;    }    public void executePay(BigDecimal amount) {        strategy.pay(amount);    }}// 使用PaymentContext context = new PaymentContext(new AlipayStrategy());context.executePay(BigDecimal.valueOf(100));context.setStrategy(new WechatPayStrategy());context.executePay(BigDecimal.valueOf(200));

Spring中的应用

  • Resource接口的不同实现:FileSystemResourceClassPathResourceUrlResource

  • BeanPostProcessor:不同实现类处理不同逻辑

4.2 模板方法模式(Template Method)

形象比喻:做菜步骤。炒菜的步骤基本固定:倒油→加热→放菜→翻炒→加调料→出锅。但具体放什么菜、什么调料,由子类决定。

public abstract class DataProcessor {    // 模板方法(final,防止子类修改结构)    public final voidprocess() {        readData();        processData();        writeData();    }    protectedabstractvoidreadData();    protectedabstractvoidprocessData();    protectedabstractvoidwriteData();}public class CsvProcessor extends DataProcessor {    @Override    protectedvoidreadData() { System.out.println("读取CSV文件"); }    @Override    protectedvoidprocessData() { System.out.println("处理CSV数据"); }    @Override    protectedvoidwriteData() { System.out.println("写入CSV结果"); }}

Spring中的应用

  • JdbcTemplateexecute()query()等模板方法

  • AbstractApplicationContextrefresh()定义了容器刷新流程

4.3 观察者模式(Observer)

形象比喻:微信公众号。你关注了一个公众号,当它发布新文章时,你会收到通知。你不需要主动去问“有新文章吗”。

// 观察者接口public interface Observer {    void update(String message);}// 被观察者(主题)public class Subject {    private List<Observer> observers = new ArrayList<>();    public void attach(Observer observer) {        observers.add(observer);    }    public void detach(Observer observer) {        observers.remove(observer);    }    public void notifyObservers(String message) {        for (Observer observer : observers) {            observer.update(message);        }    }}// 具体观察者public class EmailObserver implements Observer {    @Override    public void update(String message) {        System.out.println("发送邮件通知:" + message);    }}

Spring中的应用

  • ApplicationListenerApplicationEvent:事件驱动模型

  • Spring Cloud Bus:配置变更广播

五、框架中的设计模式识别

框架
设计模式
应用示例
Spring
工厂模式
BeanFactory

ApplicationContext
单例模式
Bean默认作用域
代理模式
AOP、@Transactional
模板方法
JdbcTemplate

RestTemplate
观察者模式
ApplicationEvent

ApplicationListener
策略模式
Resource

接口、BeanPostProcessor
装饰器模式
BufferedInputStream

装饰FileInputStream
MyBatis
建造者模式
SqlSessionFactoryBuilder
工厂模式
SqlSessionFactory
代理模式
Mapper接口动态代理
责任链模式
Interceptor

插件链
JDK
迭代器模式
Iterator

接口
代理模式
动态代理
观察者模式
java.util.Observer

(已过时,现用PropertyChangeListener
适配器模式
InputStreamReader

(字节流→字符流)

六、设计模式选型指南

场景
推荐模式
理由
需要全局唯一实例
单例
节省资源,统一访问
避免重复new对象
工厂/建造者
封装创建逻辑
需要动态增强功能
装饰器/代理
不修改原类代码
多种算法可互换
策略
消除if-else
固定流程,可变步骤
模板方法
复用骨架,定制细节
一对多通知
观察者
解耦事件发布与处理
多个对象处理同一请求
责任链
灵活组合处理者
树形结构操作
组合
统一叶子与容器

七、思维导图总结

设计模式实战├── 创建型   ├── 单例:双重检查锁枚举Spring单例Bean   ├── 工厂:BeanFactory简单工厂工厂方法抽象工厂   └── 建造者:Lombok @Builder复杂对象构建├── 结构型   ├── 代理:JDK动态代理CGLIBSpring AOP   ├── 装饰器:Java IO流动态增强   └── 适配器:InputStreamReaderHandlerAdapter├── 行为型   ├── 策略:支付方式选择Resource接口   ├── 模板方法:JdbcTemplate容器刷新流程   └── 观察者:ApplicationEventSpring Cloud Bus└── 选型决策    ├── 避免硬编码  工厂/策略    ├── 增强原有对象  代理/装饰器    └── 解耦事件处理  观察者/责任链

八、面试Tips

加分话术

  1. 单例模式:“单例模式我常用双重检查锁加volatile防止指令重排,枚举单例更安全,能防反射和序列化攻击。”

  2. 代理与装饰器:“代理模式和装饰器模式结构相似,但目的不同。代理控制访问,装饰器添加功能。Spring AOP用动态代理,Java IO用装饰器。”

  3. 工厂模式:“Spring的BeanFactory是工厂模式的经典实现。如果对象的创建逻辑复杂(如多个参数、条件分支),我会用建造者模式。”

  4. 策略模式:“支付场景用策略模式,消除了大量的if-else。策略可以运行时切换,符合开闭原则。”

常见追问准备

  • 如何破坏单例模式?(反射、序列化,枚举可防止)

  • JDK动态代理为什么必须要有接口?(生成的代理类已继承Proxy,Java单继承)

  • 模板方法和策略模式的区别?(模板方法固定算法骨架,策略模式可互换算法)

  • 为什么说观察者模式是“推”模型?(主题推送给观察者,观察者被动接收)

避坑指南

  • ❌ 不要为了用设计模式而用,过度设计

  • ❌ 不要混淆代理和装饰器

  • ❌ 单例模式注意线程安全和序列化问题

  • ✅ 优先使用框架内置的设计模式实现(如Spring的FactoryBean)

  • ✅ 多阅读框架源码,识别设计模式的应用

下期预告

【Java专题34】架构演进历程:从单体到ServiceMesh

内容预告:

  • 单体架构 → 垂直拆分 → SOA → 微服务 → ServiceMesh

  • 各阶段优缺点与适用场景

  • 架构演进的驱动力(业务、团队、技术)

  • 企业级架构升级路线图


欢迎留言:你在项目中用过哪些设计模式解决实际问题?下期我们将深入架构演进!