【Java设计模式】——单例、工厂、代理模式(2026保姆级深度版) 🛠️
大家好!这是《探索JAVA之路》设计模式系列第一篇,专攻最常用、最重要的三个模式:单例(Singleton)、工厂(Factory)、代理(Proxy)。
这三个模式几乎出现在所有Java项目中(Spring全家桶、MyBatis、日志框架、缓存、RPC……到处都是它们的影子)。学完这篇,你不仅能手写,还能一眼看出源码里的应用,面试/重构直接起飞!
1. 设计模式总览(快速定位)
三大模式定位:
- 单例:创建型 —— 确保全局只有一个实例(资源唯一)
- 工厂:创建型 —— 封装对象创建过程(解耦)
- 代理:结构型 —— 控制对真实对象的访问(增强、保护、远程)
2. 单例模式(Singleton)—— “我只存在一个”
定义:一个类只有一个实例,并提供全局访问点。
适用场景:配置管理器、线程池、数据库连接池、Spring Bean(默认单例)、日志器、缓存等。
单例模式5种实现方式对比表(2026推荐)
| 实现方式 | 线程安全 | 懒加载 | 性能 | 代码复杂度 | 推荐指数 | 备注 |
|---|---|---|---|---|---|---|
| 饿汉式(静态常量) | √ | × | 高 | ★☆☆☆☆ | 9.5 | 最推荐,简单可靠 |
| 饿汉式(静态代码块) | √ | × | 高 | ★☆☆☆☆ | 9.0 | 同上 |
| 懒汉式(synchronized) | √ | √ | 低 | ★★☆☆☆ | 6.0 | 性能差 |
| 双重校验锁(DCL) | √ | √ | 高 | ★★★☆☆ | 8.5 | 经典,但volatile必加 |
| 静态内部类(Bill Pugh) | √ | √ | 高 | ★★☆☆☆ | 9.8 | 最优雅 |
| 枚举(Enum) | √ | √ | 高 | ★☆☆☆☆ | 10.0 | 2026终极推荐,防反射/序列化 |
代码实现(最推荐两种):
// 1. 饿汉式(最简单,推荐新手直接用)
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {} // 私有构造器
public static SingletonEager getInstance() {
return INSTANCE;
}
}
// 2. 枚举单例(2026最推荐,防反射、序列化、克隆)
public enum SingletonEnum {
INSTANCE; // 天然单例
public void doSomething() {
System.out.println("我是枚举单例");
}
}
// 使用:SingletonEnum.INSTANCE.doSomething();
饿汉 vs 懒汉 vs 枚举UML思维导图:
单例破坏与防御:反射、序列化、克隆 —— 枚举天然免疫!
3. 工厂模式(Factory)—— “我来帮你造对象”
核心:将对象的创建与使用分离,符合开闭原则。
三种工厂对比表
| 类型 | 复杂度 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 简单工厂 | ★☆☆☆☆ | 简单对象创建 | 代码最少 | 不符合开闭原则 |
| 工厂方法 | ★★☆☆☆ | 需要扩展产品族 | 符合开闭原则 | 类太多 |
| 抽象工厂 | ★★★☆☆ | 产品族(多个相关产品) | 扩展产品族极强 | 结构复杂 |
简单工厂代码(日常最常用):
// 产品接口
interface Car {
void drive();
}
// 具体产品
class Tesla implements Car { public void drive() { System.out.println("特斯拉加速!"); } }
class BMW implements Car { public void drive() { System.out.println("宝马启动!"); } }
// 简单工厂
class SimpleCarFactory {
public static Car createCar(String type) {
if ("Tesla".equals(type)) return new Tesla();
if ("BMW".equals(type)) return new BMW();
throw new IllegalArgumentException("未知车型");
}
}
// 使用
Car car = SimpleCarFactory.createCar("Tesla");
car.drive();
工厂方法 & 抽象工厂UML:
实战:Spring的 BeanFactory、ApplicationContext 就是顶级工厂!
4. 代理模式(Proxy)—— “我帮你挡一下”
定义:为其他对象提供一种代理,以控制对这个对象的访问。
类型:静态代理、动态代理(JDK、CGLIB)、Spring AOP代理。
适用场景:权限控制、日志记录、事务、缓存、远程代理(RMI)、延迟加载。
静态代理代码(最清晰):
// 主题接口
interface IUserService {
void login(String username);
}
// 真实对象
class UserServiceImpl implements IUserService {
public void login(String username) {
System.out.println(username + " 登录成功");
}
}
// 代理
class UserServiceProxy implements IUserService {
private IUserService target;
public UserServiceProxy(IUserService target) { this.target = target; }
public void login(String username) {
System.out.println("【日志】有人尝试登录:" + username); // 前置增强
target.login(username);
System.out.println("【日志】登录完成"); // 后置增强
}
}
// 使用
IUserService service = new UserServiceProxy(new UserServiceImpl());
service.login("张三");
动态代理UML & 静态代理对比:
JDK动态代理(必须实现接口) vs CGLIB(基于子类,Spring默认)。
5. 三模式对比总结(面试必备)
| 模式 | 类型 | 核心目的 | 关键关键词 | Spring中体现 |
|---|---|---|---|---|
| 单例 | 创建型 | 唯一实例 | 一个实例、全局访问 | @Bean 默认 singleton |
| 工厂 | 创建型 | 封装创建逻辑 | 解耦、开闭原则 | BeanFactory、FactoryBean |
| 代理 | 结构型 | 控制访问、增强功能 | 代理、AOP | AOP、@Transactional |
一句话记忆:
- 单例:我只有一个
- 工厂:我帮你造
- 代理:我帮你挡/增强
作业(立即动手):
- 用枚举实现一个线程安全的配置单例
- 用工厂方法模式实现“支付工厂”(微信、支付宝)
- 给UserService加一个动态代理,实现登录前后日志记录
想看完整可运行Demo仓库、Spring中这三个模式的源码解析、还是结合策略/观察者模式的进阶版?
直接评论回复 “1”“2”“3”,我下一篇文章立刻奉上完整代码 + GitHub链接!
把这篇收藏 + 转发给正在学设计模式的同学吧 —— 掌握这三个模式,你的Java代码层次直接提升一个档次!✨
(本文所有代码基于JDK 17+实测,图片来自经典技术博客与UML图,欢迎对比学习)