【MapSheep】
[好记性不如烂笔头]

一、Java 常用设计模式(6 种核心,简洁易懂)

设计模式分为 3 大类:创建型、结构型、行为型,以下是面试和开发中最高频的类型。

1. 单例模式(创建型)

  • 核心思想:保证一个类在整个应用中只有一个实例,并提供全局访问点。
  • 常用实现:懒汉式(双重检查锁)、饿汉式(推荐,简单安全)。
  • 适用场景:工具类、连接池、配置类等(无需多个实例的场景)。
  • 精简代码(饿汉式,线程安全、简单)
public class Singleton {
    // 1. 私有静态常量实例(类加载时初始化,线程安全)
    private static final Singleton INSTANCE = new Singleton();
    
    // 2. 私有构造方法(防止外部 new 实例)
    private Singleton() {}
    
    // 3. 公共静态方法,返回唯一实例
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
  • 精简代码(懒汉式,双重检查锁,延迟加载)
public class SingletonLazy {
    // 1. 私有静态变量,volatile 防止指令重排
    private static volatile SingletonLazy INSTANCE;
    
    // 2. 私有构造方法
    private SingletonLazy() {}
    
    // 3. 双重检查锁,延迟加载,线程安全
    public static SingletonLazy getInstance() {
        if (INSTANCE == null) {
            synchronized (SingletonLazy.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SingletonLazy();
                }
            }
        }
        return INSTANCE;
    }
}

2. 工厂模式(创建型,含简单工厂、工厂方法、抽象工厂)

  • 核心思想:封装对象的创建过程,将创建和使用分离,降低耦合。
  • 常用实现:简单工厂(最常用,非 GOF 标准模式)、工厂方法。
  • 适用场景:对象创建复杂、需要灵活切换产品类型(如日志工厂、数据库连接工厂)。
  • 精简代码(简单工厂)
// 产品接口
public interface Product {
    void use();
}

// 具体产品 A
public class ProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品 A");
    }
}

// 简单工厂类
public class SimpleFactory {
    // 根据类型创建产品
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        } else if ("B".equals(type)) {
            return new ProductB();
        }
        return null;
    }
}

3. 代理模式(结构型,含静态代理、动态代理)

  • 核心思想:为目标对象提供一个代理,控制对目标对象的访问,可附加额外功能(如日志、事务)。
  • 常用实现:静态代理(编译期确定)、动态代理(JDK 动态代理、CGLIB,运行期生成)。
  • 适用场景:日志记录、事务管理、权限控制(如 Spring AOP 底层)。
  • 精简代码(JDK 动态代理,基于接口)
// 目标接口
public interface TargetService {
    void doSomething();
}

// 目标实现类
public class TargetServiceImpl implements TargetService {
    @Override
    public void doSomething() {
        System.out.println("目标对象执行方法");
    }
}

// 动态代理处理器
public class ProxyHandler implements InvocationHandler {
    private Object target; // 目标对象
    
    public ProxyHandler(Object target) {
        this.target = target;
    }
    
    // 代理方法,附加额外功能
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置:日志记录");
        Object result = method.invoke(target, args); // 执行目标方法
        System.out.println("后置:事务提交");
        return result;
    }
}

// 测试使用
public class ProxyTest {
    public static void main(String[] args) {
        TargetService target = new TargetServiceImpl();
        // 生成动态代理对象
        TargetService proxy = (TargetService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new ProxyHandler(target)
        );
        proxy.doSomething();
    }
}

4. 装饰者模式(结构型)

  • 核心思想:动态地给对象添加额外功能,不改变原对象结构,比继承更灵活。
  • 适用场景:需要灵活扩展对象功能(如 IO 流、Spring 包装器)。
  • 核心特点:装饰者和被装饰者实现同一接口,持有被装饰者引用。

5. 观察者模式(行为型)

  • 核心思想:定义一对多的依赖关系,当一个对象状态改变时,通知所有依赖它的对象自动更新。
  • 适用场景:事件监听、消息通知(如 GUI 事件、Spring 事件监听)。

6. 策略模式(行为型)

  • 核心思想:定义一系列算法,将每个算法封装起来,使它们可以互相替换,独立于使用算法的客户端。
  • 适用场景:多种算法可选(如排序算法、支付方式选择)。

二、高频面试题(精简版,含核心答案)

  1. 什么是单例模式?有哪些实现方式?各自的优缺点是什么?

    • 答案:① 核心:保证类只有一个实例,提供全局访问点;② 实现:饿汉式(优点:简单、线程安全;缺点:类加载时初始化,浪费内存)、懒汉式(双重检查锁,优点:延迟加载、线程安全;缺点:实现复杂,需 volatile 防止指令重排);③ 其他:静态内部类、枚举(最安全,防止反射和序列化破坏)。
  2. 单例模式中,双重检查锁为什么需要 volatile 关键字?

    • 答案:new Singleton() 分为 3 步:分配内存、初始化对象、赋值引用。JVM 可能发生指令重排,导致「引用不为 null 但对象未初始化」。volatile 可以禁止指令重排,保证多线程环境下对象的正确初始化,避免空指针异常。
  3. 工厂模式的核心思想是什么?简单工厂和工厂方法的区别是什么?

    • 答案:① 核心:封装对象创建,解耦创建与使用;② 区别:简单工厂(一个工厂创建所有产品,优点:简单;缺点:违反开闭原则,新增产品需修改工厂)、工厂方法(一个产品对应一个工厂,优点:符合开闭原则,新增产品只需新增工厂;缺点:类数量增多,复杂度提高)。
  4. 代理模式有哪些类型?JDK 动态代理和 CGLIB 有什么区别?

    • 答案:① 类型:静态代理、动态代理(JDK 动态代理、CGLIB);② 区别:JDK 动态代理(基于接口,必须实现接口,通过 Proxy.newProxyInstance() 生成代理,底层是反射)、CGLIB(基于类,无需实现接口,通过继承目标类生成代理,底层是字节码增强,性能更优,不能代理 final 类/方法)。
  5. 装饰者模式和继承的区别是什么?举例说明。

    • 答案:① 继承:静态扩展,编译期确定,子类继承父类,功能固定,灵活性差,会导致类爆炸;② 装饰者模式:动态扩展,运行期可灵活添加多个功能,不改变原对象,符合开闭原则;③ 举例:Java IO 流(BufferedReader 装饰 FileReader,动态添加缓冲功能)。
  6. 什么是策略模式?它解决了什么问题?

    • 答案:① 核心:封装一系列算法,使其可互相替换;② 解决的问题:避免大量 if-else 判断,解耦算法与客户端,符合开闭原则,新增算法只需新增策略类,无需修改客户端代码。
  7. 设计模式的 5 大原则(SOLID)是什么?

    • 答案:① 单一职责原则(一个类只负责一个职责);② 开闭原则(对扩展开放,对修改关闭);③ 里氏替换原则(子类可替换父类,不影响程序运行);④ 依赖倒置原则(依赖抽象,不依赖具体实现);⑤ 接口隔离原则(提供最小化接口,避免冗余方法)。

三、总结

  1. 面试高频设计模式:单例、工厂、代理(三大必问),其次是装饰者、观察者、策略。
  2. 答题核心:紧扣「解耦、灵活扩展、符合开闭原则」,这是设计模式的核心思想。
  3. 代码层面:重点掌握单例的双重检查锁、JDK 动态代理的实现,面试可能要求手写。
posted on 2026-02-04 18:17  (Play)  阅读(0)  评论(0)    收藏  举报