设计模式是软件开发中可复用、标准化、经过海量实战验证的代码设计经验总结,专门用于解决软件设计中反复出现的通用问题。合理使用设计模式,能够实现代码解耦、提升复用性、可维护性与扩展性,是Java高级开发、框架源码研读、面试进阶的核心必备知识点。
本文基于GoF(四人帮)定义的23种经典设计模式,按官方标准分为创建型、结构型、行为型三大类别,精选企业高频模式,搭配可直接运行的Java实战代码、核心思想、适用场景、避坑要点,同时结合Spring、MyBatis等主流框架源码案例,兼顾零基础理解与工程实战。
前言
Java设计模式的核心价值:解耦、复用、易扩展、易维护,规避硬编码、高耦合、冗余代码、难以迭代等开发痛点。
23种设计模式标准分类:
-
创建型模式(5种):专注对象创建,解耦创建逻辑与业务逻辑
-
结构型模式(7种):专注类与对象的组合搭建,优化代码结构
-
行为型模式(11种):专注对象间的交互协作、职责分配与流程控制
一、创建型模式(5种)
核心作用:封装对象创建细节,脱离原生new关键字的硬耦合,统一对象创建规范,灵活控制对象的创建数量、方式与时机。
1. 单例模式(Singleton)
核心思想:确保一个类在整个应用生命周期中有且仅有一个实例,同时提供全局统一的访问入口。
适用场景:全局工具类、系统配置类、数据库/Redis连接池、缓存工具、日志工具等需要频繁使用、无需重复创建的资源对象。
最优实现:懒汉式-双重检查锁(线程安全 + 懒加载 + 高性能)
public class Singleton {
// volatile 禁止指令重排序,解决多线程空指针问题,保证可见性
private static volatile Singleton instance;
// 私有构造方法:禁止外部通过new创建实例
private Singleton() {}
// 双重检查锁:兼顾性能与线程安全
public static Singleton getInstance() {
// 第一次校验:避免无谓加锁,提升性能
if (instance == null) {
// 类锁:保证同一时间只有一个线程进入创建逻辑
synchronized (Singleton.class) {
// 第二次校验:防止多线程穿透重复创建对象
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
框架实战应用:Spring默认单例Bean、MyBatis的SqlSessionFactory、Runtime系统工具类。
面试重点:杜绝饿汉式资源浪费、规避线程安全问题、防止反射破坏单例。
2. 工厂方法模式(Factory Method)
核心思想:定义对象创建的统一工厂接口,将具体对象的创建逻辑延迟到子类实现,一个工厂对应一种产品,满足开闭原则。
适用场景:产品种类固定、可扩展,需要灵活新增产品且不修改原有代码的场景,如多类型日志、多格式文件解析、多渠道推送。
完整实战代码
// 产品顶层接口
public interface Logger {
void log(String msg);
}
// 具体产品1:控制台日志
public class ConsoleLogger implements Logger {
@Override
public void log(String msg) {
System.out.println("控制台日志输出:" + msg);
}
}
// 具体产品2:文件日志
public class FileLogger implements Logger {
@Override
public void log(String msg) {
System.out.println("文件日志持久化:" + msg);
}
}
// 工厂顶层接口
public interface LoggerFactory {
Logger createLogger();
}
// 具体工厂1:创建控制台日志对象
public class ConsoleLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
// 具体工厂2:创建文件日志对象
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 测试调用
public class FactoryTest {
public static void main(String[] args) {
LoggerFactory factory = new ConsoleLoggerFactory();
Logger logger = factory.createLogger();
logger.log("工厂方法模式实战测试");
}
}
扩展知识:简单工厂模式(非GoF标准),由一个统一工厂类管理所有产品创建,适合产品数量少、无需频繁扩展的场景,JDK中DateFormat即为典型实现。
3. 抽象工厂模式(Abstract Factory)
核心思想:提供一个超级工厂接口,用于创建一整套相关/相互依赖的产品族,而非单个产品,可批量生产同系列产品。
适用场景:存在多套产品族、产品需配套使用的场景,如电脑硬件(联想/戴尔整套硬件)、跨系统多模块适配、多环境配置加载。
框架应用:Spring BeanFactory顶层抽象工厂、MyBatis DataSourceFactory数据源工厂。
优缺点:满足产品族整体扩展,开闭原则友好;缺点是新增产品时需改动顶层工厂,扩展单个产品成本高。
4. 建造者模式(Builder)
核心思想:将复杂对象的构建过程与对象表示分离,通过分步、链式调用构建对象,相同构建流程可生成不同属性的对象。
适用场景:对象属性多、存在必选+可选属性、参数组合复杂、构造方法臃肿的场景(实体类、配置类、参数DTO)。
企业主流链式实现(可直接复用)
public class User {
// 必选属性
private final String name;
private final int age;
// 可选属性
private String phone;
private String address;
// 私有构造方法,仅建造者可调用
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
// 静态内部建造者
public static class Builder {
// 必选属性(无默认值,强制传入)
private final String name;
private final int age;
// 可选属性(默认空值)
private String phone = "";
private String address = "";
// 构造方法强制传入必选参数
public Builder(String name, int age) {
this.name = name;
this.age = age;
}
// 链式设置可选属性
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
// 最终构建对象
public User build() {
return new User(this);
}
}
// 测试调用
public static void main(String[] args) {
User user = new User.Builder("张三", 25)
.phone("13800138000")
.address("北京市朝阳区")
.build();
}
}
框架应用:MyBatis SqlSessionFactoryBuilder、Spring BeanDefinitionBuilder、JDK StringBuilder。
5. 原型模式(Prototype)
核心思想:通过克隆已有对象实例创建新对象,替代new关键字,规避复杂对象创建的高成本问题。
适用场景:对象创建耗时久(数据库查询、远程调用、复杂计算)、对象属性相似度高、需要批量创建对象的场景。
核心实现:实现JDK Cloneable接口,重写clone()方法(浅克隆);通过序列化/反序列化实现深克隆。
框架应用:Spring Bean的prototype多例作用域,每次获取Bean均克隆新实例。
二、结构型模式(7种)
核心作用:通过继承、组合、聚合等方式,合理组装类与对象,优化代码结构,实现功能扩展、结构解耦、资源复用。
1. 代理模式(Proxy)
核心思想:为目标真实对象提供一个代理对象,由代理对象控制目标对象的访问,可在不修改目标代码的前提下,前置/后置扩展通用功能。
模式分类:静态代理(编译期生成)、动态代理(运行期动态生成,JDK动态代理、CGLIB代理)。
适用场景:权限控制、日志记录、事务管理、缓存增强、RPC远程调用、限流熔断。
JDK动态代理实战(基于接口,企业高频)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
// 目标业务接口
public interface UserService {
void queryUser(Long id);
}
// 真实目标实现类
public class UserServiceImpl implements UserService {
@Override
public void queryUser(Long id) {
System.out.println("核心业务:查询用户ID = " + id);
}
}
// 代理处理器:实现方法增强逻辑
public class ProxyHandler implements InvocationHandler {
// 被代理的真实对象
private final Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:日志、权限、参数校验
System.out.println("方法执行前置:" + method.getName() + ",参数:" + Arrays.toString(args));
// 执行目标核心方法
Object result = method.invoke(target, args);
// 后置增强:日志、统计、事务提交
System.out.println("方法执行后置:" + method.getName() + " 执行完毕");
return result;
}
}
// 测试调用
public class ProxyTest {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
// 动态生成代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new ProxyHandler(target)
);
// 通过代理调用方法
proxy.queryUser(1001L);
}
}
框架应用:Spring AOP(JDK+CGLIB双代理)、MyBatis Mapper动态代理、RPC远程服务代理。
2. 装饰器模式(Decorator)
核心思想:动态为对象叠加拓展功能,基于组合替代继承,层层包装目标对象,实现功能灵活增减、组合复用。
核心特征:装饰器与目标对象实现同一接口,持有目标对象引用,无侵入增强功能。
适用场景:功能动态叠加(缓冲、加密、压缩、日志)、避免继承体系臃肿冗余。
典型案例:JDK IO流体系
// 基础文件流(原始对象,仅实现基础读取)
FileReader fileReader = new FileReader("test.txt");
// 装饰器包装:叠加缓冲功能,增强读取性能
BufferedReader bufferedReader = new BufferedReader(fileReader);
框架应用:Spring缓存装饰器、JDK IO全套装饰流、MyBatis缓存装饰器。
3. 适配器模式(Adapter)
核心思想:将原有不兼容的接口,转换为客户端期望的目标接口,解决接口不匹配、系统不兼容问题,复用原有旧代码。
模式分类:类适配器(继承,不推荐)、对象适配器(组合,推荐,低耦合)。
适用场景:第三方组件集成、新旧系统对接、接口适配兼容、老代码复用改造。
框架应用:Spring HandlerAdapter(处理器适配)、JDK InputStreamReader(字节流转字符流)、Arrays.asList()(数组转集合)。
4. 组合模式(Composite)
核心思想:将对象构建为树形层级结构,统一单个叶子对象与整体组合对象的调用方式,实现部分与整体的一致性操作。
适用场景:树形结构数据处理,如系统菜单、部门组织树、文件目录、多级UI组件。
框架应用:MyBatis SqlNode动态SQL节点、Spring容器层级结构。
5. 享元模式(Flyweight)
核心思想:池化复用大量细粒度相似对象,减少内存占用、避免重复创建销毁对象,区分内部不变状态与外部可变状态。
适用场景:对象数量庞大、属性大部分重复,如字符串常量池、连接池、线程池。
6. 桥接模式(Bridge)
核心思想:将抽象层与实现层解耦分离,让两者可独立扩展,规避多层继承导致的类爆炸问题。
适用场景:多维度、多维度独立扩展的场景,如JDBC驱动适配、多终端多平台适配。
7. 外观模式(Facade)
核心思想:为复杂的子系统提供一个统一的高层入口,屏蔽底层复杂逻辑,简化客户端调用。
适用场景:子系统逻辑复杂、多模块协同调用,需统一封装入口的场景。
框架应用:Spring ApplicationContext容器外观,屏蔽Bean创建、依赖注入底层复杂逻辑。
三、行为型模式(11种)
核心作用:规范对象之间的通信交互、职责划分、流程调度,解决对象协作混乱、逻辑耦合、流程固化等问题。
1. 策略模式(Strategy)
核心思想:定义统一算法接口,将不同算法封装为独立策略类,算法可动态替换、独立扩展,彻底消除冗余if-else、switch分支。
适用场景:多算法、多策略切换场景,如多渠道支付、多类型排序、多数据库分页、多日志存储方式。
完整实战代码
// 策略顶层接口
public interface PayStrategy {
void pay(double amount);
}
// 具体策略:支付宝支付
public class AliPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("支付宝支付成功,金额:" + amount + "元");
}
}
// 具体策略:微信支付
public class WxPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("微信支付成功,金额:" + amount + "元");
}
}
// 上下文:统一调度策略,对外提供调用入口
public class PayContext {
private PayStrategy strategy;
// 动态切换策略
public void setStrategy(PayStrategy strategy) {
this.strategy = strategy;
}
// 执行支付逻辑
public void doPay(double amount) {
strategy.pay(amount);
}
}
// 测试调用
public class StrategyTest {
public static void main(String[] args) {
PayContext context = new PayContext();
// 切换支付宝策略
context.setStrategy(new AliPayStrategy());
context.doPay(199.9);
// 切换微信策略
context.setStrategy(new WxPayStrategy());
context.doPay(99.9);
}
}
框架应用:Spring资源加载策略、MyBatis多数据库分页策略。
2. 观察者模式(Observer)
核心思想:定义一对多订阅依赖,被观察者状态变更时,自动通知所有订阅的观察者,实现事件驱动、解耦发布与订阅。
适用场景:消息通知、事件监听、状态回调,如订单支付成功后的库存扣减、物流创建、积分发放。
框架应用:Spring事件机制(ApplicationEvent+ApplicationListener)、Guava EventBus、MQ消息订阅。
3. 模板方法模式(Template Method)
核心思想:父类定义固定的算法流程骨架,将可变的业务步骤抽象为方法,由子类按需实现,固定流程、灵活定制。
适用场景:多业务流程统一、仅局部步骤不同的场景,如数据库操作、文件解析、接口回调。
实战代码
// 抽象模板类:定义流程骨架
public abstract class DbTemplate {
// final修饰:禁止子类重写,保证流程固定
public final void execute() {
getConnection();
doExecuteSql();
closeConnection();
}
// 固定通用步骤
private void getConnection() {
System.out.println("获取数据库连接");
}
private void closeConnection() {
System.out.println("关闭数据库连接,释放资源");
}
// 可变步骤:抽象方法,子类自定义实现
protected abstract void doExecuteSql();
}
// 子类:查询SQL实现
public class QueryTemplate extends DbTemplate {
@Override
protected void doExecuteSql() {
System.out.println("执行查询SQL:select * from user");
}
}
// 子类:插入SQL实现
public class InsertTemplate extends DbTemplate {
@Override
protected void doExecuteSql() {
System.out.println("执行插入SQL:insert into user(name,age) values('李四',28)");
}
}
// 测试调用
public class TemplateTest {
public static void main(String[] args) {
new QueryTemplate().execute();
new InsertTemplate().execute();
}
}
框架应用:Spring JdbcTemplate、MyBatis BaseExecutor、HttpServlet doGet/doPost方法。
4. 迭代器模式(Iterator)
核心思想:提供统一的元素遍历接口,屏蔽聚合对象的内部结构,统一各类集合的遍历方式。
框架应用:JDK所有集合的Iterator迭代器、Spring Iterable遍历体系。
5. 其他高频行为型模式
-
责任链模式:将多个处理器串联成链,请求逐级传递处理,如SpringMVC拦截器链、过滤器链、MyBatis插件链。
-
命令模式:将请求封装为独立命令对象,解耦请求发起与请求处理,支持命令撤销、重试、排队。
-
状态模式:将对象不同状态封装为独立状态类,对象行为随状态自动切换,如订单状态、审批流程状态流转。
四、设计模式核心基石:SOLID五大设计原则
所有设计模式均基于SOLID原则衍生,原则是道,模式是术,理解原则才能灵活选用模式,避免过度设计。
1. 单一职责原则(SRP)
核心:一个类/方法/接口只负责唯一一项核心职责。
正反案例:禁止一个实体类同时承担数据存储、业务逻辑、文件导出功能;拆分后各司其职,修改互不影响。
价值:降低bug风险、简化迭代维护、提升代码可读性。
2. 开闭原则(OCP,核心原则)
核心:对扩展开放,对修改关闭。稳定成熟的代码禁止修改,新增功能通过扩展实现。
正反案例:支付功能新增渠道时,不修改原有支付逻辑,新建支付策略类扩展,保证线上代码稳定。
3. 里氏替换原则(LSP)
核心:子类可完全替换父类,且不破坏原有程序逻辑,子类不能削弱父类能力。
避坑:禁止子类重写父类方法后抛出异常、修改返回值、改变业务逻辑。
4. 接口隔离原则(ISP)
核心:拆分臃肿大接口,提供多个细粒度小接口,客户端只依赖自己需要的接口。
价值:避免空实现冗余、减少无效依赖、提升代码整洁度。
5. 依赖倒置原则(DIP)
核心:高层依赖抽象,不依赖具体实现,基于接口编程,而非直接new具体类。
实战体现:Spring依赖注入,业务层只依赖接口,具体实现可动态替换,无需修改核心代码。
五、主流框架设计模式汇总(面试高频)
1. Spring框架
单例模式(Bean默认单例)、工厂模式(BeanFactory)、代理模式(AOP)、模板方法(JdbcTemplate)、观察者(事件监听)、适配器(HandlerAdapter)
2. MyBatis框架
代理模式(Mapper动态代理)、建造者模式(SqlSessionFactoryBuilder)、工厂模式(SqlSessionFactory)、策略模式(多数据库适配)、模板方法(执行器)
3. JDK源码
装饰器模式(IO流)、迭代器模式(集合)、单例模式(Runtime)、适配器模式(流转换)、工厂模式(DateFormat)
六、实战学习建议
-
先原则、后模式:吃透SOLID原则,才能理解模式设计初衷,不死记硬背;
-
抓高频、弃冷门:优先掌握单例、工厂、代理、策略、模板、建造者6大核心模式,覆盖90%开发场景;
-
结合源码学实战:通过Spring/MyBatis源码理解模式落地方式,告别纸上谈兵;
-
拒绝过度设计:简单业务无需套用模式,复杂迭代场景按需使用,优先保证代码简洁。
七、全文核心总结
Java 23种设计模式分为创建型、结构型、行为型三大体系,核心目标统一为解耦、复用、可扩展、易维护。所有模式均服务于业务开发,无优劣之分,只有场景适配之别。
开发与面试核心重点:熟记高频模式思想、熟练手写核心代码、掌握框架落地场景、能够根据业务选型。
整理不易,请不要举报啦!!!