【Java专题33】设计模式实战:从源码到架构的23种模式应用
面试场景还原
面试官:“你在项目中用过哪些设计模式?工厂模式和策略模式有什么区别?Spring中用了哪些设计模式?你能现场写一个线程安全的单例吗?装饰器模式和代理模式的区别是什么?”
你:(脑海中浮现出23种模式的全景图,从创建型到行为型,从源码到应用场景逐层展开…)
考察重点
这道题是中高级工程师的核心题,面试官想考察:
-
模式理解:能否准确说出常用设计模式的意图、结构和适用场景
-
源码识别:能否在常用框架(Spring、MyBatis、JDK)中识别设计模式的应用
-
实战能力:能否根据业务场景选择合适的模式,并给出实现
-
架构思维:能否在系统设计中灵活组合设计模式解决问题
一、设计模式全景图
┌─────────────────────────────────────────────────────────────────┐│ 设计模式分类 │├─────────────────────────────────────────────────────────────────┤│ ││ 创建型(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();default: throw new IllegalArgumentException("未知支付类型");}}}
// 产品接口public interface Payment {void pay(BigDecimal amount);}// 具体产品public class Alipay implements Payment {@Overridepublic void pay(BigDecimal amount) {System.out.println("支付宝支付:" + amount);}}// 工厂接口public interface PaymentFactory {Payment createPayment();}// 具体工厂public class AlipayFactory implements PaymentFactory {@Overridepublic 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 {@Overridepublic 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;}@Overridepublic void createOrder(Order order) {System.out.println("开始创建订单,时间:" + System.currentTimeMillis());target.createOrder(order);System.out.println("订单创建完成");}}
public class LogProxyHandler implements InvocationHandler {private final Object target;public LogProxyHandler(Object target) {this.target = target;}@Overridepublic 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));}}
public classCglibInterceptorimplementsMethodInterceptor{@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxyproxy) throwsThrowable{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 {@Overridepublic String getDescription() { return "简单咖啡"; }@Overridepublic 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); }@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 奶";}@Overridepublic double getCost() {return decoratedCoffee.getCost() + 1.5;}}
代理 vs 装饰器:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
Java IO中的应用:BufferedInputStream装饰FileInputStream,增加缓冲功能。
四、行为型模式实战
4.1 策略模式(Strategy)
形象比喻:出行方式选择。去机场可以打车、坐地铁、骑自行车。每种方式都是一个策略,你可以根据需要随时切换。
// 策略接口public interface PaymentStrategy {void pay(BigDecimal amount);}// 具体策略:支付宝public class AlipayStrategy implements PaymentStrategy {@Overridepublic void pay(BigDecimal amount) {System.out.println("使用支付宝支付:" + amount);}}// 具体策略:微信public class WechatPayStrategy implements PaymentStrategy {@Overridepublic 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接口的不同实现:FileSystemResource、ClassPathResource、UrlResource -
BeanPostProcessor:不同实现类处理不同逻辑
4.2 模板方法模式(Template Method)
形象比喻:做菜步骤。炒菜的步骤基本固定:倒油→加热→放菜→翻炒→加调料→出锅。但具体放什么菜、什么调料,由子类决定。
public abstract class DataProcessor {// 模板方法(final,防止子类修改结构)public final voidprocess() {readData();processData();writeData();}protectedabstractvoidreadData();protectedabstractvoidprocessData();protectedabstractvoidwriteData();}public class CsvProcessor extends DataProcessor {@OverrideprotectedvoidreadData() { System.out.println("读取CSV文件"); }@OverrideprotectedvoidprocessData() { System.out.println("处理CSV数据"); }@OverrideprotectedvoidwriteData() { System.out.println("写入CSV结果"); }}
Spring中的应用:
-
JdbcTemplate的execute()、query()等模板方法 -
AbstractApplicationContext的refresh()定义了容器刷新流程
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 {@Overridepublic void update(String message) {System.out.println("发送邮件通知:" + message);}}
Spring中的应用:
-
ApplicationListener和ApplicationEvent:事件驱动模型 -
Spring Cloud Bus:配置变更广播
五、框架中的设计模式识别
|
|
|
|
|---|---|---|
| Spring |
|
BeanFactory
ApplicationContext |
|
|
|
|
|
|
@Transactional |
|
|
|
JdbcTemplate
RestTemplate |
|
|
|
ApplicationEvent
ApplicationListener |
|
|
|
Resource
BeanPostProcessor |
|
|
|
BufferedInputStream
FileInputStream |
|
| MyBatis |
|
SqlSessionFactoryBuilder |
|
|
SqlSessionFactory |
|
|
|
|
|
|
|
Interceptor
|
|
| JDK |
|
Iterator
|
|
|
|
|
|
|
java.util.Observer
PropertyChangeListener) |
|
|
|
InputStreamReader
|
六、设计模式选型指南
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
七、思维导图总结
设计模式实战├── 创建型│ ├── 单例:双重检查锁、枚举、Spring单例Bean│ ├── 工厂:BeanFactory、简单工厂→工厂方法→抽象工厂│ └── 建造者:Lombok @Builder、复杂对象构建├── 结构型│ ├── 代理:JDK动态代理、CGLIB、Spring AOP│ ├── 装饰器:Java IO流、动态增强│ └── 适配器:InputStreamReader、HandlerAdapter├── 行为型│ ├── 策略:支付方式选择、Resource接口│ ├── 模板方法:JdbcTemplate、容器刷新流程│ └── 观察者:ApplicationEvent、Spring Cloud Bus└── 选型决策├── 避免硬编码 → 工厂/策略├── 增强原有对象 → 代理/装饰器└── 解耦事件处理 → 观察者/责任链
八、面试Tips
加分话术
-
单例模式:“单例模式我常用双重检查锁加volatile防止指令重排,枚举单例更安全,能防反射和序列化攻击。”
-
代理与装饰器:“代理模式和装饰器模式结构相似,但目的不同。代理控制访问,装饰器添加功能。Spring AOP用动态代理,Java IO用装饰器。”
-
工厂模式:“Spring的BeanFactory是工厂模式的经典实现。如果对象的创建逻辑复杂(如多个参数、条件分支),我会用建造者模式。”
-
策略模式:“支付场景用策略模式,消除了大量的if-else。策略可以运行时切换,符合开闭原则。”
常见追问准备
-
如何破坏单例模式?(反射、序列化,枚举可防止)
-
JDK动态代理为什么必须要有接口?(生成的代理类已继承Proxy,Java单继承)
-
模板方法和策略模式的区别?(模板方法固定算法骨架,策略模式可互换算法)
-
为什么说观察者模式是“推”模型?(主题推送给观察者,观察者被动接收)
避坑指南
-
❌ 不要为了用设计模式而用,过度设计
-
❌ 不要混淆代理和装饰器
-
❌ 单例模式注意线程安全和序列化问题
-
✅ 优先使用框架内置的设计模式实现(如Spring的FactoryBean)
-
✅ 多阅读框架源码,识别设计模式的应用
下期预告
【Java专题34】架构演进历程:从单体到ServiceMesh
内容预告:
-
单体架构 → 垂直拆分 → SOA → 微服务 → ServiceMesh
-
各阶段优缺点与适用场景
-
架构演进的驱动力(业务、团队、技术)
-
企业级架构升级路线图
欢迎留言:你在项目中用过哪些设计模式解决实际问题?下期我们将深入架构演进!
夜雨聆风