Java中的设计模式
常见设计模式 + 单例模式
面试一句话:GoF23种设计模式,分为创建型、结构型、行为型;面试重点掌握常用的即可。
一、常见设计模式
1. 创建型模式(管对象创建)
- 单例模式 Singleton:保证一个类全局只有一个实例,并提供全局访问点。
- 工厂方法 Factory Method:定义创建对象接口,子类决定实例化哪一个类。
- 抽象工厂 Abstract Factory:创建一系列相关/相互依赖对象。
- 建造者 Builder:分步构建复杂对象,分离构建与表示。
- 原型 Prototype:克隆已有对象来创建新对象。
2. 结构型模式(类/对象组合,组装)
- 适配器 Adapter:把一个类接口转换成客户端期望的另一个接口。
- 装饰器 Decorator:动态给对象增加额外功能,不修改原有代码。
- 代理 Proxy:控制对象访问,在访问前后增加逻辑(SpringAOP动态代理)。
- 组合 Composite:树结构,统一对待单个对象和容器对象。
- 外观 Facade:提供统一入口,封装复杂子系统。
- 享元 Flyweight:复用大量细粒度对象,减少内存占用。
- 桥接 Bridge:分离抽象与实现,两者可以独立扩展。
3. 行为型模式(对象之间通信、职责分配)
- 策略 Strategy:封装一组算法,可互相替换。
- 观察者 Observer:事件订阅通知,发布订阅模式。
- 模板方法 Template Method:父类定义骨架,子类实现可变步骤。
- 责任链 Chain of Responsibility:请求沿着链传递,直到被处理。
- 迭代器 Iterator:遍历集合,不暴露底层结构。
- 状态 State:对象内部状态改变时改变行为。
- 命令 Command:把请求封装成对象。
其他如备忘录、解释器、访问者,面试问得很少。
二、单例模式:常见实现、线程安全
面试一句话:单例目标,保证整个应用中该类只有一个实例,提供全局访问点。
1. 饿汉式(线程安全)
类加载的时候直接实例化,JVM类加载机制保证线程安全;缺点类加载就创建,不用也占用内存。
public class HungrySingleton {
// 类加载直接初始化
private static final HungrySingleton INSTANCE = new HungrySingleton();
// 私有构造,防止外部new
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return INSTANCE;
}
}
✅ 线程安全;❌ 类加载就创建,不支持懒加载。
2. 懒汉式(非线程安全,面试反面例子)
调用 getInstance 才创建,多线程环境会创建多个实例。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton(){}
public static LazySingleton getInstance(){
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
❌ 多线程不安全,并发进入 if 会多次实例化。
3. DCL 双重检查锁(Double-Check Locking,推荐)
volatile + 两次判空 + synchronized,懒加载,线程安全。
public class DclSingleton {
// volatile 禁止指令重排
private static volatile DclSingleton instance;
private DclSingleton(){}
public static DclSingleton getInstance(){
if(instance == null){ // 第一次检查
synchronized (DclSingleton.class){
if(instance == null){ // 第二次检查
instance = new DclSingleton();
}
}
}
return instance;
}
}
volatile 作用:防止
new 对象的指令重排(分配内存、初始化对象、赋值引用顺序错乱,返回半初始化对象)
4. 静态内部类(推荐,优雅)
利用 JVM 类加载,外部类加载不会加载内部类,调用时才加载;天然线程安全,懒加载
public class InnerSingleton {
private InnerSingleton(){}
// 静态内部类
private static class SingletonHolder{
private static final InnerSingleton INSTANCE = new InnerSingleton();
}
public static InnerSingleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
✅ 懒加载,JVM 保证线程安全,无锁。
5. 枚举单例(Effective Java 推荐,防止反射、序列化破坏)
public enum EnumSingleton{
INSTANCE;
//业务方法
public void doSomething(){}
}
✅ 线程安全,天然防反射、防序列化破坏单例;
❌ 饿汉式,类加载就实例化。
三、面试高频追问
1. 如何保证线程安全?
- 饿汉式:JVM 类加载机制,类初始化阶段只执行一次,天然安全。
- DCL:synchronized 加锁 + volatile 禁止指令重排。
- 静态内部类:JVM 加载静态内部类时只会初始化一次,天然线程安全。
- 枚举:枚举实例创建由 JVM 保证,天然线程安全。
2. 破坏单例的方式
- 反射:暴力调用私有构造器(枚举可以抵御反射)
- 序列化与反序列化:反序列化会生成新对象(枚举天然抵御)

浙公网安备 33010602011771号