Java设计模式面试题分类整理

一、创建型模式

1. 单例模式 (Singleton)

面试题:如何实现线程安全的单例模式?有哪些实现方式?

答案:
单例模式就是确保一个类只有一个实例,并提供全局访问点。

实现方式:

  1. 饿汉式:类加载时就创建实例,线程安全但可能浪费资源
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}
  1. 懒汉式(双重检查锁定):第一次使用时才创建实例,线程安全且高效
public class Singleton {
    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;
    }
}
  1. 静态内部类:利用类加载机制保证线程安全,延迟加载
public class Singleton {
    private Singleton() {}
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}
  1. 枚举:最简洁的线程安全实现,还能防止反序列化破坏单例
public enum Singleton {
    INSTANCE;
}

2. 工厂模式 (Factory)

面试题:简单工厂、工厂方法和抽象工厂有什么区别?

答案:

  • 简单工厂:一个工厂类根据参数创建不同产品
    • 优点:客户端不关心创建细节
    • 缺点:新增产品需要修改工厂类,违反开闭原则
    • 适用场景:产品种类较少且不常变化
  • 工厂方法:定义一个创建对象的接口,让子类决定实例化哪个类
    • 优点:新增产品只需新增工厂子类,符合开闭原则
    • 缺点:类数量增多
    • 适用场景:产品种类较多且可能扩展
  • 抽象工厂:创建一组相关或依赖对象的接口,无需指定具体类
    • 优点:可以保证产品族的兼容性
    • 缺点:扩展产品族困难
    • 适用场景:需要创建一系列相关产品对象

3. 建造者模式 (Builder)

面试题:建造者模式和工厂模式有什么区别?

答案:

  • 建造者模式:
    • 关注对象的构建过程,可以分步骤构建复杂对象
    • 适用于构造参数多且有可选参数的场景
    • 通常有一个Director类指导构建过程
    • 示例:StringBuilder、AlertDialog.Builder
  • 工厂模式:
    • 关注对象的创建结果,直接返回完整对象
    • 适用于创建单一产品
    • 不关心构建过程细节

建造者模式示例:

public class Computer {
    private String cpu;
    private String memory;
    // 其他属性...
    
    public static class Builder {
        private String cpu;
        private String memory;
        
        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        
        public Builder setMemory(String memory) {
            this.memory = memory;
            return this;
        }
        
        public Computer build() {
            Computer computer = new Computer();
            computer.cpu = this.cpu;
            computer.memory = this.memory;
            return computer;
        }
    }
}

二、结构型模式

1. 适配器模式 (Adapter)

面试题:什么是适配器模式?有哪些实现方式?

答案:
适配器模式就像电源转换插头,让不兼容的接口能够一起工作。

两种实现方式:

  1. 类适配器:通过继承实现
public class Adapter extends Adaptee implements Target {
    public void request() {
        super.specificRequest();
    }
}
  1. 对象适配器:通过组合实现(更常用)
public class Adapter implements Target {
    private Adaptee adaptee;
    
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    
    public void request() {
        adaptee.specificRequest();
    }
}

应用场景:

  • 旧系统改造,需要复用现有类
  • 使用第三方库,接口不匹配时
  • 统一多个类的接口

2. 装饰器模式 (Decorator)

面试题:装饰器模式和继承有什么区别?

答案:

  • 装饰器模式:
    • 动态地为对象添加功能,运行时决定
    • 通过组合实现,更灵活
    • 可以嵌套多个装饰器
    • 示例:Java IO流体系
  • 继承:
    • 静态地扩展功能,编译时决定
    • 通过继承实现,不够灵活
    • 容易导致类爆炸

装饰器示例:

public interface Coffee {
    double getCost();
    String getDescription();
}

public class SimpleCoffee implements Coffee {
    // 实现方法...
}

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    public double getCost() {
        return decoratedCoffee.getCost();
    }
    
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
}

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public double getCost() {
        return super.getCost() + 0.5;
    }
    
    public String getDescription() {
        return super.getDescription() + ", milk";
    }
}

3. 代理模式 (Proxy)

面试题:静态代理和动态代理有什么区别?

答案:

  • 静态代理:
    • 手动编写代理类
    • 一个代理类对应一个目标类
    • 编译时确定代理关系
    • 实现简单但维护成本高
  • 动态代理:
    • 运行时动态生成代理类
    • 一个代理类可以代理多个目标类
    • 需要反射机制支持
    • JDK动态代理(基于接口)和CGLib(基于继承)

JDK动态代理示例:

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    public void request() {
        System.out.println("Real request");
    }
}

public class ProxyHandler implements InvocationHandler {
    private Object target;
    
    public ProxyHandler(Object target) {
        this.target = target;
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before request");
        Object result = method.invoke(target, args);
        System.out.println("After request");
        return result;
    }
}

// 使用
Subject subject = (Subject) Proxy.newProxyInstance(
    RealSubject.class.getClassLoader(),
    RealSubject.class.getInterfaces(),
    new ProxyHandler(new RealSubject())
);
subject.request();

三、行为型模式

1. 观察者模式 (Observer)

面试题:Java中有哪些观察者模式的实现?

答案:
观察者模式就像订阅报纸,出版者(Subject)维护订阅者(Observer)列表,状态变化时通知所有订阅者。

Java内置实现:

// 过时的实现(不推荐)
import java.util.Observable;
import java.util.Observer;

// 现代实现(推荐)
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;
    
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(state);
        }
    }
    // 其他方法...
}

Java事件机制也是观察者模式的实现,如Swing中的事件监听。

2. 策略模式 (Strategy)

面试题:策略模式如何避免if-else?

答案:
策略模式定义一系列算法,封装每个算法,并使它们可以互换。

实现步骤:

  1. 定义策略接口
  2. 实现具体策略类
  3. 使用Context类维护策略引用

示例:

public interface PaymentStrategy {
    void pay(int amount);
}

public class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("信用卡支付:" + amount);
    }
}

public class AlipayPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

public class PaymentContext {
    private PaymentStrategy strategy;
    
    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executePayment(int amount) {
        strategy.pay(amount);
    }
}

// 使用
PaymentContext context = new PaymentContext(new AlipayPayment());
context.executePayment(100);

3. 责任链模式 (Chain of Responsibility)

面试题:责任链模式在哪些框架中有应用?

答案:
责任链模式让多个对象都有机会处理请求,从而避免请求发送者和接收者耦合。

应用场景:

  • Java Servlet中的Filter链
  • Spring MVC中的拦截器链
  • 日志框架中的多Appender处理

示例:

public abstract class Handler {
    protected Handler next;
    
    public void setNext(Handler next) {
        this.next = next;
    }
    
    public abstract void handleRequest(Request request);
}

public class ConcreteHandlerA extends Handler {
    public void handleRequest(Request request) {
        if (canHandle(request)) {
            // 处理请求
        } else if (next != null) {
            next.handleRequest(request);
        }
    }
    // 其他方法...
}

// 使用
Handler chain = new ConcreteHandlerA();
chain.setNext(new ConcreteHandlerB());
chain.handleRequest(request);

四、其他重要模式

1. 模板方法模式 (Template Method)

面试题:模板方法模式和策略模式有什么区别?

答案:

  • 模板方法模式:
    • 基于继承
    • 定义算法骨架,子类实现某些步骤
    • 控制算法流程在父类
    • 示例:AbstractList、HttpServlet
  • 策略模式:
    • 基于组合
    • 定义算法家族,可以互换
    • 控制算法流程在客户端
    • 示例:Comparator

模板方法示例:

public abstract class Game {
    // 模板方法
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
    
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();
}

public class Cricket extends Game {
    void initialize() { /* 实现 */ }
    void startPlay() { /* 实现 */ }
    void endPlay() { /* 实现 */ }
}

2. 外观模式 (Facade)

面试题:外观模式和适配器模式有什么区别?

答案:

  • 外观模式:
    • 为复杂子系统提供简化接口
    • 目的是简化使用
    • 不改变原有接口
    • 示例:SLF4J
  • 适配器模式:
    • 使不兼容接口能够协同工作
    • 目的是解决兼容性问题
    • 会改变原有接口
    • 示例:InputStreamReader

外观模式示例:

public class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;
    
    public ComputerFacade() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
    }
    
    public void start() {
        cpu.freeze();
        memory.load();
        cpu.jump();
        cpu.execute();
    }
}

五、设计模式综合问题

1. 如何选择合适的设计模式?

答案:
选择设计模式应考虑以下因素:

  1. 问题类型:
    • 创建对象 → 工厂、建造者、原型
    • 对象组合 → 适配器、桥接、装饰器
    • 对象行为 → 策略、状态、观察者
  2. 设计原则:
    • 开闭原则 → 策略、装饰器
    • 单一职责 → 外观、代理
    • 依赖倒置 → 依赖注入
  3. 项目阶段:
    • 初期:工厂、单例、策略
    • 重构:适配器、装饰器、观察者
    • 扩展:抽象工厂、责任链

2. 设计模式的优缺点?

答案:
​​优点​​:

  • 提供标准解决方案
  • 提高代码复用性
  • 提高可维护性
  • 促进团队沟通

缺点:

  • 过度使用会增加复杂性
  • 学习曲线较陡
  • 可能引入不必要的抽象
  • 某些模式可能降低性能

3. Spring框架中使用了哪些设计模式?

答案:

  1. 工厂模式:BeanFactory
  2. 单例模式:默认的Bean作用域
  3. 代理模式:AOP实现
  4. 模板方法:JdbcTemplate, RestTemplate
  5. 观察者模式:ApplicationEvent
  6. 适配器模式:HandlerAdapter
  7. 装饰器模式:BeanWrapper
  8. 策略模式:Resource接口的不同实现
  9. 责任链模式:Spring Security的过滤器链
  10. 建造者模式:BeanDefinitionBuilder
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐