AIGC标识 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. 如何保证线程安全?

  1. 饿汉式:JVM 类加载机制,类初始化阶段只执行一次,天然安全。
  2. DCL:synchronized 加锁 + volatile 禁止指令重排。
  3. 静态内部类:JVM 加载静态内部类时只会初始化一次,天然线程安全。
  4. 枚举:枚举实例创建由 JVM 保证,天然线程安全。

2. 破坏单例的方式

  • 反射:暴力调用私有构造器(枚举可以抵御反射)
  • 序列化与反序列化:反序列化会生成新对象(枚举天然抵御)
posted @ 2026-09-26 15:24  赵登科  阅读(3)  评论(0)    收藏  举报