设计模式是Java开发领域沉淀的"最佳实践",是解决特定场景下重复问题的标准化模板。它并非语法规则,而是一套兼顾代码可复用性、可扩展性、可维护性的设计思想。多数开发者对设计模式的认知停留在"背定义、写Demo",但真正的价值在于将其融入业务开发与框架源码中,实现"写得优雅、改得轻松"。本文从设计模式核心原则出发,拆解三大类高频模式,结合Java实战代码与主流框架应用场景,帮助开发者建立"场景→模式→落地"的系统化思维,真正吃透设计模式的实用价值。
一、设计模式前置:核心原则与分类
1. 六大设计原则(设计模式的基石)
所有设计模式均围绕以下六大原则展开,核心目标是降低耦合、提升内聚,避免代码"僵硬、脆弱"。
| 原则名称 | 核心定义 | 核心作用 |
|---|---|---|
| 单一职责原则(SRP) | 一个类只负责一项职责,避免功能冗余 | 降低类的复杂度,减少需求变更带来的影响 |
| 开闭原则(OCP) | 对扩展开放,对修改关闭 | 通过扩展新增功能,避免修改原有稳定代码 |
| 里氏替换原则(LSP) | 子类可替换父类,且不改变原有程序逻辑 | 保障继承体系的稳定性,支持多态复用 |
| 依赖倒置原则(DIP) | 依赖抽象而非具体实现,面向接口编程 | 降低模块间耦合,提升系统扩展性 |
| 接口隔离原则(ISP) | 拆分庞大接口为专用小接口,避免冗余方法 | 减少接口依赖,降低类的实现成本 |
| 迪米特法则(LOD) | 类只与直接关联对象通信,减少依赖范围 | 降低系统复杂度,减少模块间交互成本 |
| 核心提醒:原则并非"铁律",需结合业务场景灵活权衡。例如简单业务可适当放宽单一职责,避免过度设计导致类数量激增。 |
2. 设计模式三大分类
Java中23种经典设计模式可按功能分为三大类,覆盖"对象创建、结构组合、行为交互"全场景:
- 创建型模式(5种):控制对象创建过程,隐藏创建细节,实现对象复用与解耦(如单例、工厂、建造者)。
- 结构型模式(7种):优化对象与类的结构组合,实现功能扩展与耦合降低(如代理、装饰器、适配器)。
- 行为型模式(11种):规范对象间的交互行为,实现职责分配与通信解耦(如观察者、策略、责任链)。
二、创建型模式:优雅创建对象,隐藏实现细节
创建型模式核心解决"如何灵活创建对象"的问题,避免直接通过new关键字硬编码,降低对象创建与业务逻辑的耦合。
1. 单例模式(Singleton)
核心原理
保证一个类在整个应用中仅有一个实例,并提供全局访问点。适用于工具类、配置类、线程池等场景(避免重复创建资源消耗)。
实战实现(推荐方案)
单例模式需兼顾线程安全、懒加载、效率三大要素,不同实现方案各有优劣,推荐以下两种工业级方案:
java
// 方案1:静态内部类(推荐,线程安全、懒加载、无锁高效)
public class Singleton {
// 私有构造器,禁止外部实例化
private Singleton() {}
// 静态内部类,懒加载实例(类加载时才初始化)
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 全局访问点
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
// 方案2:枚举单例(极简,天然线程安全、防反射、防序列化破坏)
public enum EnumSingleton {
INSTANCE;
// 业务方法
public void doSomething() {
System.out.println("枚举单例执行逻辑");
}
}
框架应用
Spring中的Bean默认是单例模式(通过容器管理实例生命周期);JDK中的Runtime.getRuntime()也是经典单例实现。
2. 工厂方法模式(Factory Method)
核心原理
定义一个创建对象的接口,由子类决定具体创建哪种对象,实现"创建逻辑"与"业务逻辑"分离。适用于产品种类固定、需灵活扩展产品的场景。
实战实现
java
// 1. 产品接口(抽象)
public interface Product {
void produce();
}
// 2. 具体产品实现
public class PhoneProduct implements Product {
@Override
public void produce() {
System.out.println("生产手机");
}
}
public class ComputerProduct implements Product {
@Override
public void produce() {
System.out.println("生产电脑");
}
}
// 3. 工厂接口(抽象创建逻辑)
public interface Factory {
Product createProduct();
}
// 4. 具体工厂实现(对应具体产品)
public class PhoneFactory implements Factory {
@Override
public Product createProduct() {
return new PhoneProduct();
}
}
public class ComputerFactory implements Factory {
@Override
public Product createProduct() {
return new ComputerProduct();
}
}
// 客户端调用(无需关心创建细节,只依赖抽象)
public class Client {
public static void main(String[] args) {
Factory factory = new PhoneFactory();
Product product = factory.createProduct();
product.produce(); // 输出:生产手机
}
}
扩展:简单工厂模式
若产品种类较少,可简化为"简单工厂"(一个工厂类负责所有产品创建),但违背开闭原则(新增产品需修改工厂类),适用于简单场景。
3. 建造者模式(Builder)
核心原理
将复杂对象的构建过程与表示分离,分步构建对象,支持灵活组合不同属性。适用于对象属性多、构造复杂的场景(如订单、用户信息、配置类)。
实战实现(Lombok简化版)
java
import lombok.Builder;
import lombok.Data;
// 复杂对象(通过Lombok @Builder自动生成建造者)
@Data
@Builder
public class Order {
private String orderNo; // 订单号(必填)
private String userId; // 用户ID(必填)
private double amount; // 金额(必填)
private String address; // 收货地址(可选)
private String remark; // 备注(可选)
}
// 客户端调用(链式构建,清晰灵活)
public class Client {
public static void main(String[] args) {
Order order = Order.builder()
.orderNo("ORDER2024001")
.userId("USER123")
.amount(999.0)
.address("北京市朝阳区")
.build();
}
}
手动实现建造者模式需定义Builder内部类,分步设置属性并提供build()方法,Lombok可大幅简化代码。
三、结构型模式:优化对象结构,实现功能扩展
结构型模式通过组合、继承等方式优化对象与类的结构,在不修改原有代码的前提下扩展功能,契合开闭原则。
1. 代理模式(Proxy)
核心原理
为目标对象提供一个代理对象,控制对目标对象的访问,可在访问前后添加额外逻辑(如日志、权限校验、缓存)。分为静态代理、动态代理(JDK动态代理、CGLIB)。
实战实现(JDK动态代理)
java
// 1. 目标接口
public interface UserService {
void queryUser(String userId);
}
// 2. 目标对象(核心业务逻辑)
public class UserServiceImpl implements UserService {
@Override
public void queryUser(String userId) {
System.out.println("查询用户信息,用户ID:" + userId);
}
}
// 3. 动态代理处理器(增强逻辑)
public class LogProxyHandler implements InvocationHandler {
private Object target; // 目标对象
public LogProxyHandler(Object target) {
this.target = target;
}
// 代理逻辑:调用目标方法前打印日志
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:打印日志
System.out.println("开始调用方法:" + method.getName() + ",参数:" + args[0]);
// 调用目标对象方法
Object result = method.invoke(target, args);
// 后置增强(可选)
System.out.println("方法调用结束");
return result;
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
// 目标对象
UserService userService = new UserServiceImpl();
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new LogProxyHandler(userService)
);
// 调用代理方法(触发增强逻辑)
proxy.queryUser("USER123");
}
}
框架应用
Spring AOP的核心是动态代理:JDK动态代理用于代理接口,CGLIB用于代理类;MyBatis的Mapper接口也是通过动态代理生成实现类。
2. 装饰器模式(Decorator)
核心原理
动态为对象添加额外功能,通过组合替代继承,实现功能的灵活扩展。与代理模式的区别:装饰器关注"增强功能",代理模式关注"控制访问"。
实战实现(IO流案例)
JDK的IO流是装饰器模式的经典应用,如BufferedReader、InputStreamReader均为装饰器类。
java
// 1. 核心组件(抽象)
public interface Stream {
void read();
}
// 2. 原始组件(被装饰对象)
public class FileStream implements Stream {
@Override
public void read() {
System.out.println("读取文件原始数据");
}
}
// 3. 装饰器抽象类(持有核心组件引用)
public abstract class StreamDecorator implements Stream {
protected Stream stream;
public StreamDecorator(Stream stream) {
this.stream = stream;
}
}
// 4. 具体装饰器(添加缓冲功能)
public class BufferedStreamDecorator extends StreamDecorator {
public BufferedStreamDecorator(Stream stream) {
super(stream);
}
@Override
public void read() {
System.out.println("添加缓冲功能,提升读取效率");
stream.read(); // 调用原始组件方法
}
}
// 客户端调用(多层装饰)
public class Client {
public static void main(String[] args) {
Stream stream = new BufferedStreamDecorator(new FileStream());
stream.read(); // 输出:添加缓冲功能... 读取文件原始数据
}
}
3. 适配器模式(Adapter)
核心原理
将一个类的接口转换成客户端期望的另一个接口,解决不同接口间的兼容性问题。适用于集成第三方组件、旧系统改造场景。
实战实现(类适配器)
java
// 1. 客户端期望的目标接口
public interface Target {
void request();
}
// 2. 适配者(第三方组件/旧系统接口,与目标接口不兼容)
public class Adaptee {
public void specificRequest() {
System.out.println("第三方组件的特殊接口逻辑");
}
}
// 3. 适配器(继承适配者,实现目标接口,转换逻辑)
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
super.specificRequest(); // 调用适配者方法,适配为目标接口
}
}
// 客户端调用(依赖目标接口,无需关心适配细节)
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request(); // 输出:第三方组件的特殊接口逻辑
}
}
四、行为型模式:规范对象交互,解耦行为职责
行为型模式聚焦对象间的通信与职责分配,通过定义清晰的交互规则,降低对象间的耦合,提升代码的可扩展性。
1. 观察者模式(Observer)
核心原理
定义对象间的一对多依赖关系,当被观察者状态变化时,自动通知所有观察者并更新。适用于事件通知、消息订阅场景(如发布-订阅模式)。
实战实现(JDK自带观察者)
java
import java.util.Observable;
import java.util.Observer;
// 1. 被观察者(主题)
public class MessageSubject extends Observable {
private String message;
public void setMessage(String message) {
this.message = message;
setChanged(); // 标记状态已变化
notifyObservers(message); // 通知所有观察者
}
}
// 2. 观察者1(邮件通知)
public class EmailObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("邮件通知:收到新消息 - " + arg);
}
}
// 3. 观察者2(短信通知)
public class SmsObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("短信通知:收到新消息 - " + arg);
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
MessageSubject subject = new MessageSubject();
// 注册观察者
subject.addObserver(new EmailObserver());
subject.addObserver(new SmsObserver());
// 改变状态,触发通知
subject.setMessage("Hello, 观察者模式!");
}
}
Spring中的ApplicationEvent与ApplicationListener也是观察者模式的实现,用于Spring容器内的事件通知。
2. 策略模式(Strategy)
核心原理
定义一系列算法,将每种算法封装为独立类,支持算法的动态切换,避免大量if-else分支。适用于多种算法可选、需灵活切换的场景(如支付方式、排序算法)。
实战实现
java
// 1. 策略接口(抽象算法)
public interface PayStrategy {
void pay(double amount);
}
// 2. 具体策略(支付宝支付)
public class AlipayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
}
// 3. 具体策略(微信支付)
public class WechatPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
}
}
// 4. 上下文(封装策略,提供切换入口)
public class PayContext {
private PayStrategy strategy;
// 构造器注入策略
public PayContext(PayStrategy strategy) {
this.strategy = strategy;
}
// 切换策略
public void setStrategy(PayStrategy strategy) {
this.strategy = strategy;
}
// 执行支付
public void executePay(double amount) {
strategy.pay(amount);
}
}
// 客户端调用(动态切换策略)
public class Client {
public static void main(String[] args) {
PayContext context = new PayContext(new AlipayStrategy());
context.executePay(100.0); // 支付宝支付
context.setStrategy(new WechatPayStrategy());
context.executePay(200.0); // 切换为微信支付
}
}
3. 责任链模式(Chain of Responsibility)
核心原理
将请求的处理者连成一条链,请求沿链传递,直到有处理者处理该请求。适用于多角色、多级别处理请求的场景(如权限校验、日志分级处理)。
实战实现
java
// 1. 请求对象
public class Request {
private String content; // 请求内容
private int level; // 请求级别(1-普通,2-中级,3-高级)
// getter/setter
}
// 2. 处理者抽象类
public abstract class Handler {
protected Handler nextHandler; // 下一个处理者
// 设置下一个处理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 处理请求(子类实现具体逻辑)
public abstract void handleRequest(Request request);
}
// 3. 具体处理者(普通级别)
public class NormalHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getLevel() == 1) {
System.out.println("普通处理者处理请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request); // 传递给下一个处理者
}
}
}
// 4. 具体处理者(高级级别)
public class HighHandler extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getLevel() == 3) {
System.out.println("高级处理者处理请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 客户端调用(构建责任链)
public class Client {
public static void main(String[] args) {
// 构建处理者
Handler normalHandler = new NormalHandler();
Handler highHandler = new HighHandler();
// 构建责任链:普通→高级
normalHandler.setNextHandler(highHandler);
// 发送请求
Request request1 = new Request();
request1.setLevel(1);
request1.setContent("普通请求");
normalHandler.handleRequest(request1); // 普通处理者处理
Request request2 = new Request();
request2.setLevel(3);
request2.setContent("高级请求");
normalHandler.handleRequest(request2); // 高级处理者处理
}
}
五、设计模式实战误区与避坑指南
1. 典型误区
- 误区一:过度设计,滥用模式:简单业务强行套用复杂模式(如单表CRUD用工厂+代理+策略),导致代码冗余、可读性下降。
- 误区二:死记模式,忽略场景:只背定义不理解适用场景,如用装饰器模式替代继承,反而增加系统复杂度。
- 误区三:混淆相似模式:代理、装饰器、适配器模式易混淆,核心区别在于"意图"(控制访问、增强功能、接口适配)。
- 误区四:忽视框架封装的模式:Spring、MyBatis已封装大量设计模式,无需重复造轮子(如Spring的依赖注入替代手动工厂模式)。
2. 避坑关键动作
-
先解决问题,再优化结构:业务初期优先实现功能,待需求稳定后,再基于设计原则重构为设计模式。
-
结合框架使用模式:优先利用框架自带的模式实现(如Spring的Bean管理、AOP),减少手动编码成本。
-
聚焦核心模式:23种模式中,10种左右为高频模式(单例、工厂、代理、观察者、策略等),优先掌握这些模式的实战应用。
-
通过源码学习模式:阅读JDK、Spring、MyBatis源码,理解模式在工业级项目中的实际应用(如Spring的BeanFactory是工厂模式)。
六、总结:设计模式的核心价值是"优雅解决问题"
设计模式的本质不是"炫技",而是一套经过实践验证的"问题解决方案"。它的核心价值的是帮助开发者写出"高内聚、低耦合、可扩展"的代码,让系统在需求迭代中保持稳定,降低维护成本。
对Java开发者而言,掌握设计模式的关键的是:理解原则、记住场景、灵活应用。不必追求掌握所有23种模式,而是针对实际业务场景,选择最合适的模式解决问题;同时通过阅读框架源码,学习工业级的模式应用技巧,将设计模式真正融入日常开发,从"能实现"迈向"会设计"。
后续可深入学习:设计模式的组合使用(如工厂+策略、代理+装饰器)、并发场景下的设计模式(如生产者-消费者模式)、DDD领域设计与设计模式的结合,进一步提升系统设计能力。