【MS核心】Java 设计模式

设计模式是 Java 面试的高频核心考点,面试官聚焦核心概念、应用场景、代码实现、优缺点、实际落地五大维度,以下是分类型的高频问题及标准答案,适配初/中/高级面试场景:

一、通用基础问题(必背)

1. 设计模式的核心原则(SOLID 原则)?各自的含义?

SOLID 是面向对象设计的基石,也是设计模式的底层逻辑:

原则 英文全称 核心含义 反例/场景
单一职责(S) Single Responsibility 一个类只负责一个功能模块,避免“万能类” 一个 UserService 既处理用户逻辑又处理订单逻辑
开闭原则(O) Open/Closed 对扩展开放,对修改关闭(通过抽象/接口扩展) 新增支付方式时,无需修改原有支付逻辑代码
里氏替换(L) Liskov Substitution 子类可替换父类且不改变程序原有行为 正方形不能继承矩形(修改边长会破坏矩形逻辑)
接口隔离(I) Interface Segregation 拆分臃肿接口为多个专用接口,避免“接口污染” 一个 PayInterface 拆分出 WechatPay/Alipay 接口
依赖倒置(D) Dependency Inversion 依赖抽象而非具体实现(面向接口编程) 依赖 Logger 接口而非 FileLogger 实现类

2. 设计模式分为哪几类?每类的核心目的?

类型 核心目的 代表模式 适用场景
创建型 封装对象的创建过程,解耦“创建”与“使用” 单例、工厂方法、抽象工厂、建造者、原型 对象创建复杂(如多参数对象、不同类型对象)
结构型 优化类/对象的组合方式,提升灵活性 代理、适配器、装饰器、桥接、组合、外观、享元 类结构扩展(如功能增强、接口适配)
行为型 规范对象间的交互方式,提升协作效率 策略、模板方法、观察者、迭代器、责任链、命令、状态 对象通信/流程控制(如事件通知、流程复用)

3. 设计模式的核心价值是什么?为什么要使用?

  • 核心价值:代码复用、解耦、可扩展、易维护、符合面向对象设计原则
  • 具体作用:
    1. 解决通用问题(如单例解决资源独占,代理解决权限控制);
    2. 提升代码可读性(符合行业通用规范,便于团队协作);
    3. 降低维护成本(扩展功能时无需修改原有代码,符合开闭原则);
    4. 避免重复造轮子(复用成熟的设计思路,减少bug)。

二、创建型模式(高频考点)

1. 单例模式

(1)单例模式的核心特点?有哪些实现方式?

  • 核心特点:保证一个类只有一个实例,且提供全局访问点;
  • 常见实现方式(按推荐优先级排序):
    实现方式 核心代码 线程安全 懒加载 适用场景
    枚举单例 enum Singleton { INSTANCE; } 简单场景(无懒加载需求,最优解)
    双重检查锁(DCL) private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) instance = new Singleton(); } } return instance; } 懒加载+高性能(生产首选)
    静态内部类 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } 懒加载(无锁,性能优)
    饿汉式 private static final Singleton INSTANCE = new Singleton(); 实例创建成本低(如工具类)
    懒汉式(同步方法) public synchronized static Singleton getInstance() 低并发(性能差,不推荐)

(2)DCL 为什么要加 volatile?

  • 原因:instance = new Singleton() 不是原子操作,分为 3 步:① 分配内存;② 初始化对象;③ 引用指向内存;
  • JVM 可能重排序(①→③→②),导致其他线程拿到“半初始化”的实例;
  • volatile 禁止指令重排序,保证实例初始化完成后才被其他线程可见。

(3)单例模式的优缺点?

  • 优点:节省内存、避免资源重复创建(如数据库连接池);
  • 缺点:
    • 违背单一职责(既负责业务逻辑又负责实例管理);
    • 不利于测试(单例无法被 mock,耦合度高);
    • 多线程下若实现不当,可能出现多个实例。

(4)Spring 中的单例实现?

  • Spring Bean 默认是单例(非线程安全),通过 DefaultSingletonBeanRegistry 维护一个 HashMap 存储单例实例;
  • 与传统单例的区别:Spring 单例是“容器级”(一个 Bean 名称对应一个实例),而非“类级”(多个容器可创建多个实例)。

2. 工厂模式

(1)工厂模式分为哪几种?核心区别?

模式类型 核心实现 适用场景
简单工厂(非GOF) 一个工厂类根据参数创建不同实例(如 ProductFactory.createProduct("A") 产品类型少、创建逻辑简单
工厂方法 抽象工厂类+多个具体工厂类(每个工厂创建一种产品) 产品类型扩展频繁(新增产品只需加工厂)
抽象工厂 一个工厂创建一组相关产品(如手机工厂创建手机+充电器) 产品族扩展(如不同品牌的全套产品)

(2)代码示例(工厂方法):

// 抽象产品
public interface Pay {
    void pay();
}
// 具体产品
public class Alipay implements Pay {
    @Override
    public void pay() { System.out.println("支付宝支付"); }
}
public class WechatPay implements Pay {
    @Override
    public void pay() { System.out.println("微信支付"); }
}
// 抽象工厂
public interface PayFactory {
    Pay createPay();
}
// 具体工厂
public class AlipayFactory implements PayFactory {
    @Override
    public Pay createPay() { return new Alipay(); }
}
public class WechatPayFactory implements PayFactory {
    @Override
    public Pay createPay() { return new WechatPay(); }
}
// 使用
public class Client {
    public static void main(String[] args) {
        PayFactory factory = new AlipayFactory();
        Pay pay = factory.createPay();
        pay.pay();
    }
}

(3)工厂模式的核心价值?Spring 中的应用?

  • 核心价值:解耦“产品创建”与“产品使用”,符合依赖倒置原则(依赖抽象而非具体);
  • Spring 应用:
    • BeanFactory 是工厂模式的核心(ApplicationContext 继承自 BeanFactory);
    • FactoryBean 用于创建复杂 Bean(如 MyBatis 的 SqlSessionFactoryBean)。

3. 建造者模式

(1)建造者模式的核心作用?与工厂模式的区别?

  • 核心作用:构建复杂对象(多参数、可选参数),分步构建、统一组装(如 User 对象有姓名、年龄、地址等可选字段);
  • 与工厂模式的区别:
    • 工厂模式:关注“创建”,直接返回产品实例;
    • 建造者模式:关注“构建过程”,分步设置属性,最后组装返回。

(2)代码示例(链式建造者):

public class User {
    private String name;
    private Integer age;
    private String address;
    
    // 私有构造器
    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.address = builder.address;
    }
    
    // 静态内部建造者
    public static class Builder {
        private String name;
        private Integer age;
        private String address;
        
        public Builder name(String name) {
            this.name = name;
            return this;
        }
        public Builder age(Integer age) {
            this.age = age;
            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()
                .name("张三")
                .age(20)
                .address("北京")
                .build();
    }
}

(3)建造者模式的应用场景?

  • 复杂对象构建(如 StringBuilder、MyBatis 的 SqlSessionFactoryBuilder);
  • 多参数对象(尤其是可选参数多),避免构造器参数过多( Telescoping Constructor 反模式)。

三、结构型模式(高频考点)

1. 代理模式

(1)代理模式分为哪几种?核心区别?

类型 实现方式 适用场景 示例
静态代理 手动编写代理类,实现与目标类相同接口 代理逻辑固定(如简单的权限控制) 自定义 UserServiceProxy 代理 UserService
动态代理 JDK 动态代理(基于接口) 代理多个类,接口统一 Spring AOP(JDK 代理)
CGLIB 动态代理(基于继承) 目标类无接口 Spring AOP(CGLIB 代理)

(2)JDK 动态代理 vs CGLIB 动态代理?

维度 JDK 动态代理 CGLIB 动态代理
底层实现 反射 + 接口实现 ASM 字节码生成 + 继承目标类
要求 目标类必须实现接口 目标类不能是 final(无法继承)
性能 JDK 8+ 性能优于 CGLIB 生成子类耗时,运行时性能略高
方法增强 只能代理接口方法 可代理所有方法(包括非接口方法)

(3)代码示例(JDK 动态代理):

// 目标接口
public interface UserService {
    void addUser();
}
// 目标类
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        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 Client {
    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.addUser();
    }
}

(4)代理模式的核心应用?

  • Spring AOP(核心是动态代理,实现横切逻辑如事务、日志、权限);
  • MyBatis 的 Mapper 代理(动态生成 Mapper 实现类,避免手动编写);
  • RPC 框架(如 Dubbo 的服务代理,实现远程调用)。

2. 装饰器模式

(1)装饰器模式的核心作用?与继承的区别?

  • 核心作用:动态给对象添加功能,不改变原有类结构(符合开闭原则);
  • 与继承的区别:
    • 继承:静态扩展(编译期确定,子类膨胀);
    • 装饰器:动态扩展(运行期组合,灵活添加/移除功能)。

(2)代码示例(IO 流装饰器):

// 抽象组件
public interface Stream {
    void write(String data);
}
// 具体组件
public class FileStream implements Stream {
    @Override
    public void write(String data) {
        System.out.println("写入文件:" + data);
    }
}
// 抽象装饰器
public abstract class StreamDecorator implements Stream {
    protected Stream stream;
    public StreamDecorator(Stream stream) {
        this.stream = stream;
    }
}
// 具体装饰器:加密装饰
public class EncryptDecorator extends StreamDecorator {
    public EncryptDecorator(Stream stream) {
        super(stream);
    }
    @Override
    public void write(String data) {
        // 加密处理
        String encryptData = data + "_encrypt";
        // 调用原有功能
        stream.write(encryptData);
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        Stream stream = new EncryptDecorator(new FileStream());
        stream.write("hello"); // 输出:写入文件:hello_encrypt
    }
}

(3)装饰器模式的应用场景?

  • JDK IO 流(如 BufferedReader 装饰 ReaderDataOutputStream 装饰 OutputStream);
  • Spring 的 TransactionAwareCacheDecorator(装饰缓存,增加事务支持)。

3. 适配器模式

(1)适配器模式的核心作用?分为哪几种?

  • 核心作用:将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题;
  • 分类:
    • 类适配器(继承):目标类 + 适配者类(Java 单继承,少用);
    • 对象适配器(组合):持有适配者实例(推荐,更灵活);
    • 接口适配器(默认适配器):空实现接口方法,子类按需重写(如 MouseAdapter)。

(2)代码示例(对象适配器):

// 客户端期望的接口
public interface Payment {
    void pay();
}
// 适配者(第三方接口,接口不兼容)
public class AlipaySDK {
    public void doAlipay() {
        System.out.println("支付宝支付SDK");
    }
}
// 适配器
public class AlipayAdapter implements Payment {
    private AlipaySDK alipaySDK;
    public AlipayAdapter(AlipaySDK alipaySDK) {
        this.alipaySDK = alipaySDK;
    }
    @Override
    public void pay() {
        // 适配第三方接口
        alipaySDK.doAlipay();
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        Payment payment = new AlipayAdapter(new AlipaySDK());
        payment.pay();
    }
}

(3)适配器模式 vs 装饰器模式?

维度 适配器模式 装饰器模式
核心目的 解决接口不兼容 扩展对象功能
结构 持有适配者实例(组合) 持有被装饰者实例(组合)
接口 改变原有接口 保持原有接口
场景 集成第三方组件(接口不一致) 动态添加功能(如 IO 流缓冲)

4. 外观模式(门面模式)

(1)核心作用?应用场景?

  • 核心作用:为复杂子系统提供统一入口,简化客户端调用(如 OrderService 整合库存、支付、物流子系统);
  • 应用场景:
    • 简化复杂 API 调用(如 JDBC 封装为 JdbcTemplate);
    • 微服务网关(整合多个微服务接口,提供统一入口)。

(2)代码示例:

// 子系统1:库存服务
public class InventoryService {
    public void reduceStock() { System.out.println("扣减库存"); }
}
// 子系统2:支付服务
public class PayService {
    public void pay() { System.out.println("支付扣款"); }
}
// 子系统3:物流服务
public class LogisticsService {
    public void createOrder() { System.out.println("创建物流订单"); }
}
// 外观类
public class OrderFacade {
    private InventoryService inventoryService = new InventoryService();
    private PayService payService = new PayService();
    private LogisticsService logisticsService = new LogisticsService();
    
    // 统一入口
    public void createOrder() {
        inventoryService.reduceStock();
        payService.pay();
        logisticsService.createOrder();
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        OrderFacade facade = new OrderFacade();
        facade.createOrder(); // 一行代码调用多个子系统
    }
}

四、行为型模式(高频考点)

1. 策略模式

(1)核心作用?解决什么问题?

  • 核心作用:定义一组算法,封装每个算法,使算法可互相替换(客户端无感知);
  • 解决问题:避免大量 if-else/switch 分支(如不同支付方式、不同排序算法)。

(2)代码示例:

// 策略接口
public interface SortStrategy {
    void sort(int[] arr);
}
// 具体策略:冒泡排序
public class BubbleSort implements SortStrategy {
    @Override
    public void sort(int[] arr) { System.out.println("冒泡排序"); }
}
// 具体策略:快速排序
public class QuickSort implements SortStrategy {
    @Override
    public void sort(int[] arr) { System.out.println("快速排序"); }
}
// 上下文
public class Sorter {
    private SortStrategy strategy;
    public Sorter(SortStrategy strategy) {
        this.strategy = strategy;
    }
    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    public void sortArray(int[] arr) {
        strategy.sort(arr);
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        Sorter sorter = new Sorter(new BubbleSort());
        sorter.sortArray(new int[]{1,3,2});
        // 切换策略
        sorter.setStrategy(new QuickSort());
        sorter.sortArray(new int[]{1,3,2});
    }
}

(3)策略模式的应用场景?

  • Spring 的 Resource 接口(不同资源加载策略:文件、类路径、URL);
  • MyBatis 的 Executor 接口(不同执行器策略:SimpleExecutor、BatchExecutor);
  • 电商的优惠策略(满减、折扣、优惠券)。

2. 模板方法模式

(1)核心作用?核心结构?

  • 核心作用:定义算法骨架,将可变步骤延迟到子类实现(复用固定逻辑,扩展可变逻辑);
  • 核心结构:
    • 抽象父类:定义模板方法(固定算法流程)+ 抽象方法(可变步骤);
    • 具体子类:实现抽象方法,定制可变步骤。

(2)代码示例:

// 抽象父类
public abstract class AbstractTemplate {
    // 模板方法(final 防止子类重写)
    public final void process() {
        // 固定步骤1
        step1();
        // 可变步骤(子类实现)
        step2();
        // 固定步骤3
        step3();
    }
    private void step1() { System.out.println("固定步骤1:初始化"); }
    protected abstract void step2(); // 可变步骤
    private void step3() { System.out.println("固定步骤3:完成"); }
}
// 具体子类1
public class ConcreteTemplate1 extends AbstractTemplate {
    @Override
    protected void step2() { System.out.println("子类1:执行业务逻辑A"); }
}
// 具体子类2
public class ConcreteTemplate2 extends AbstractTemplate {
    @Override
    protected void step2() { System.out.println("子类2:执行业务逻辑B"); }
}
// 使用
public class Client {
    public static void main(String[] args) {
        AbstractTemplate template = new ConcreteTemplate1();
        template.process();
    }
}

(3)模板方法模式的应用?

  • Spring 的 JdbcTemplate(固定 JDBC 流程,子类实现 RowMapper 处理结果);
  • Servlet 的 doGet/doPostservice 方法是模板方法,子类实现具体逻辑);
  • MyBatis 的 BaseExecutor(固定执行流程,子类实现具体执行逻辑)。

3. 观察者模式

(1)核心作用?核心角色?

  • 核心作用:定义对象间的一对多依赖,当一个对象状态变化时,所有依赖者自动收到通知;
  • 核心角色:
    • 主题(Subject):维护观察者列表,提供注册/移除/通知方法;
    • 观察者(Observer):定义更新方法,接收主题通知。

(2)代码示例(JDK 自带 Observer/Observable):

// 主题(被观察者)
public class WeatherData extends Observable {
    private float temperature;
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        setChanged(); // 标记状态变化
        notifyObservers(temperature); // 通知观察者
    }
}
// 观察者1:控制台显示
public class ConsoleDisplay implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("当前温度:" + arg);
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        weatherData.addObserver(new ConsoleDisplay());
        weatherData.setTemperature(25.0f); // 输出:当前温度:25.0
    }
}

(3)观察者模式的应用?

  • Spring 的事件监听机制(ApplicationEvent/ApplicationListener);
  • Guava 的 EventBus(简化观察者模式实现);
  • 消息队列(如 RocketMQ 的生产者/消费者模型)。

4. 责任链模式

(1)核心作用?核心结构?

  • 核心作用:将请求的处理者连成一条链,请求沿链传递,直到被处理(解耦请求发送者和处理者);
  • 核心结构:
    • 抽象处理器:定义处理方法 + 设置下一个处理器;
    • 具体处理器:实现处理逻辑,若无法处理则传递给下一个。

(2)代码示例:

// 抽象处理器
public abstract class Handler {
    protected Handler nextHandler;
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
    public abstract void handleRequest(String request);
}
// 具体处理器1:权限校验
public class AuthHandler extends Handler {
    @Override
    public void handleRequest(String request) {
        if ("login".equals(request)) {
            System.out.println("权限校验通过");
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            }
        } else {
            System.out.println("权限校验失败");
        }
    }
}
// 具体处理器2:日志记录
public class LogHandler extends Handler {
    @Override
    public void handleRequest(String request) {
        System.out.println("日志记录:" + request);
    }
}
// 使用
public class Client {
    public static void main(String[] args) {
        Handler authHandler = new AuthHandler();
        Handler logHandler = new LogHandler();
        authHandler.setNextHandler(logHandler);
        authHandler.handleRequest("login"); // 输出:权限校验通过 → 日志记录:login
    }
}

(3)责任链模式的应用?

  • Spring MVC 的 HandlerInterceptor(拦截器链);
  • Servlet 的 Filter(过滤器链);
  • Dubbo 的 Filter(过滤器链);
  • MyBatis 的 Interceptor(插件链)。

五、面试高频扩展问题

1. 设计模式在 Spring 中的应用有哪些?

模式 Spring 应用场景
单例模式 Bean 默认单例(DefaultSingletonBeanRegistry
工厂模式 BeanFactory/FactoryBean 创建 Bean
代理模式 AOP 动态代理(JDK/CGLIB)
装饰器模式 TransactionAwareCacheDecorator 装饰缓存
模板方法 JdbcTemplate/RestTemplate 固定流程
观察者模式 事件监听(ApplicationEvent/ApplicationListener
责任链模式 HandlerInterceptor 拦截器链
策略模式 Resource 资源加载策略、TransactionManager 事务管理器

2. 如何选择设计模式?核心思路?

  • 先明确问题:是“创建对象”“组合类/对象”还是“协调对象交互”;
  • 遵循 SOLID 原则:优先保证代码可扩展、可维护;
  • 避免过度设计:简单场景用简单方案(如简单工厂优于抽象工厂);
  • 结合业务场景:
    • 复杂对象创建 → 建造者模式;
    • 功能动态扩展 → 装饰器模式;
    • 接口不兼容 → 适配器模式;
    • 分支逻辑多 → 策略模式。

3. 设计模式的常见反模式?

  • 滥用单例:所有类都设计为单例,导致耦合高、测试难;
  • 过度继承:用继承代替组合/装饰器,导致类爆炸;
  • 万能工厂:一个工厂类创建所有产品,违反单一职责;
  • 硬编码依赖:直接 new 实例,而非依赖注入(违反依赖倒置)。

4. 组合模式 vs 装饰器模式?

  • 组合模式:处理“部分-整体”结构(如树形结构:部门→员工),关注对象的层级组合;
  • 装饰器模式:处理“功能扩展”,关注对象的功能增强,无层级关系。

六、面试速记口诀

  1. 设计原则记 SOLID,开闭原则是核心;
  2. 创建型:单例(DCL)、工厂(解耦创建)、建造者(复杂对象);
  3. 结构型:代理(增强)、装饰(扩展)、适配器(兼容)、外观(简化);
  4. 行为型:策略(去分支)、模板(固定流程)、观察者(通知)、责任链(传递);
  5. Spring 核心用代理(AOP)、工厂(Bean)、模板(Jdbc)、观察者(事件)。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容