Java设计模式面试题分类整理
·
Java设计模式面试题分类整理
一、创建型模式
1. 单例模式 (Singleton)
面试题:如何实现线程安全的单例模式?有哪些实现方式?
答案:
单例模式就是确保一个类只有一个实例,并提供全局访问点。
实现方式:
- 饿汉式:类加载时就创建实例,线程安全但可能浪费资源
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
- 懒汉式(双重检查锁定):第一次使用时才创建实例,线程安全且高效
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;
}
}
- 静态内部类:利用类加载机制保证线程安全,延迟加载
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
- 枚举:最简洁的线程安全实现,还能防止反序列化破坏单例
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)
面试题:什么是适配器模式?有哪些实现方式?
答案:
适配器模式就像电源转换插头,让不兼容的接口能够一起工作。
两种实现方式:
- 类适配器:通过继承实现
public class Adapter extends Adaptee implements Target {
public void request() {
super.specificRequest();
}
}
- 对象适配器:通过组合实现(更常用)
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?
答案:
策略模式定义一系列算法,封装每个算法,并使它们可以互换。
实现步骤:
- 定义策略接口
- 实现具体策略类
- 使用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. 如何选择合适的设计模式?
答案:
选择设计模式应考虑以下因素:
- 问题类型:
- 创建对象 → 工厂、建造者、原型
- 对象组合 → 适配器、桥接、装饰器
- 对象行为 → 策略、状态、观察者
- 设计原则:
- 开闭原则 → 策略、装饰器
- 单一职责 → 外观、代理
- 依赖倒置 → 依赖注入
- 项目阶段:
- 初期:工厂、单例、策略
- 重构:适配器、装饰器、观察者
- 扩展:抽象工厂、责任链
2. 设计模式的优缺点?
答案:
优点:
- 提供标准解决方案
- 提高代码复用性
- 提高可维护性
- 促进团队沟通
缺点:
- 过度使用会增加复杂性
- 学习曲线较陡
- 可能引入不必要的抽象
- 某些模式可能降低性能
3. Spring框架中使用了哪些设计模式?
答案:
- 工厂模式:BeanFactory
- 单例模式:默认的Bean作用域
- 代理模式:AOP实现
- 模板方法:JdbcTemplate, RestTemplate
- 观察者模式:ApplicationEvent
- 适配器模式:HandlerAdapter
- 装饰器模式:BeanWrapper
- 策略模式:Resource接口的不同实现
- 责任链模式:Spring Security的过滤器链
- 建造者模式:BeanDefinitionBuilder
更多推荐
所有评论(0)