```html
欢迎来到考acca网 | 专注技术面试与架构设计解析

【壹】设计模式综述:面试的基石

在软件工程中,设计模式(Design Patterns)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。在技术面试中,面试常考的设计者模式往往占据了相当大的比重,尤其是对于中高级Java、前端及架构师岗位。

设计模式并非具体的代码,而是一种思想,一种解决特定问题的模板。面试官考察设计模式,不仅仅是看你是否背熟了代码,更是考察你是否有良好的代码架构意识,是否能在实际业务中灵活运用这些模式来降低耦合、提高扩展性。

⚡ 创建型模式

关注对象的创建机制,改变创建方式可以更好地控制对象的创建过程。包括单例、工厂、抽象工厂、建造者、原型模式。

⚙️ 结构型模式

关注类与对象的组合,通过继承类和组合对象来获得更大的结构。包括适配器、桥接、组合、装饰、外观、享元、代理模式。

🔄 行为型模式

关注对象之间的通信,以及对象如何分配职责。包括模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器。

【贰】单例模式:唯一实例的艺术

单例模式(Singleton Pattern)是面试中出现频率极高的模式,尤其是其各种实现方式的线程安全性讨论。单例模式确保一个类只有一个实例,并提供一个全局访问点。

1. 常见实现方式对比

实现方式 线程安全 延迟加载 优缺点分析
饿汉式 是 否 简单,类加载即创建,浪费内存,但线程安全。
懒汉式(同步方法) 是 是 效率低,每次调用都同步,不推荐。
懒汉式(双重检查锁) 是 是 推荐。利用volatile防止指令重排,兼顾性能与安全。
静态内部类 是 是 推荐。利用类加载机制保证线程安全,结构优雅。
枚举单例 是 否 最推荐。防止反射攻击,防止序列化破坏,简洁高效。

2. 代码示例:双重检查锁(DCL)

public class Singleton {
    // volatile 防止指令重排
    private volatile static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

3. 面试陷阱

【叁】工厂模式:解耦的利器

工厂模式(Factory Pattern)主要用于创建对象,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1. 简单工厂模式

虽然简单工厂模式不属于23种设计模式之一(因为它违背了开闭原则),但在面试中常作为切入点。它通过一个工厂类根据传入的参数决定创建哪种产品类的实例。

2. 工厂方法模式

定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式让类的实例化推迟到子类。

3. 抽象工厂模式

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。适用于创建一系列相关或依赖的对象。

简单工厂示例

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;
    }
}

缺点:增加新产品需要修改工厂类代码,违反开闭原则。

工厂方法示例

public interface ProductFactory {
    Product create();
}
public class ConcreteFactoryA implements ProductFactory {
    public Product create() {
        return new ProductA();
    }
}

优点:符合开闭原则,增加新产品只需增加新工厂类。

抽象工厂示例

抽象工厂模式通常用于生产一组相关对象,如UI组件库(Windows风格 vs Mac风格)。每个工厂负责生产一套完整的组件。

public interface AbstractFactory {
    Button createButton();
    Checkbox createCheckbox();
}

【肆】观察者模式:事件驱动的核心

观察者模式(Observer Pattern)定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。这是Java中非常常用的模式,尤其在Spring框架的事件机制、前端的事件总线中广泛应用。

1. 核心角色

2. 应用场景

在面试中,当被问到“如何实现消息队列”或“如何实现事件通知”时,观察者模式是一个很好的切入点。例如,Spring的ApplicationContextEvent就是基于观察者模式实现的。

3. 代码示例

// 主题接口
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
// 观察者接口
public interface Observer {
    void update(String message);
}

【伍】策略模式:消除条件判断

策略模式(Strategy Pattern)定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。它解决了多重条件判断语句(if-else或switch-case)带来的代码臃肿问题。

1. 典型场景

电商平台的优惠计算、支付渠道选择、排序算法选择等。如果不用策略模式,代码中会充斥着大量的if-else,难以维护。

2. 实现思路

定义策略接口,每个具体策略实现该接口。上下文类持有策略接口的引用,调用时根据条件注入不同的策略实现。

优点

符合开闭原则,易于扩展新策略;避免使用多重条件判断语句;算法可以互相替换。

缺点

客户端必须知道所有的策略类,并决定使用哪一个;产生大量的策略类对象。

【陆】面试高频问答:面试官在想什么?

Q1: 什么是开闭原则?

开闭原则(Open-Closed Principle)是面向对象设计中最基础的原则。软件实体应当对扩展开放,对修改关闭。也就是说,当需求变化时,我们应该通过添加新代码来扩展功能,而不是修改现有代码。设计模式的核心目的之一就是实现开闭原则。

Q2: 为什么推荐使用接口而不是抽象类?

接口支持多重实现,而抽象类只能单继承。接口定义契约,抽象类定义类型。在微服务架构中,接口更利于解耦和测试。但在需要共享代码时,抽象类更有优势。面试中通常建议优先使用接口,除非需要共享状态或代码。

Q3: 装饰器模式和代理模式的区别?

装饰器模式旨在动态地给对象添加职责,强调功能的增强;代理模式旨在控制对对象的访问,强调权限或延迟加载。虽然两者结构相似,但意图不同。装饰器通常透明地增强功能,而代理通常对客户隐藏真实对象。

Q4: 如何在实际项目中应用设计模式?

不要为了用模式而用模式。当发现代码中存在重复的逻辑、难以扩展的条件判断、或紧耦合的依赖时,考虑引入设计模式。例如,当支付渠道增加时,使用策略模式;当需要创建复杂对象时,使用建造者模式。设计模式是工具,解决实际问题才是目的。

```
斌知网
蜀ICP备2026017620号-5