以下是针对Java设计模式的面试题,涵盖常见模式的定义、应用场景、代码示例及优缺点分析,适合评估候选人对设计模式的理解和实际应用能力:
1. 单例模式
题目:
- 请描述单例模式的实现方式,并说明如何实现线程安全的单例模式。
- 举一个单例模式的实际应用场景,并解释其优势。
参考答案:
-
实现方式:
- 饿汉式:类加载时初始化实例(线程安全,但可能存在资源浪费)
public class Singleton {private static final 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;} }
- 饿汉式:类加载时初始化实例(线程安全,但可能存在资源浪费)
-
应用场景:
- 数据库连接池:确保全局唯一实例,避免频繁创建/销毁连接。
- 日志记录器:统一管理日志输出,避免多个实例导致日志混乱。
-
优势:
- 节省内存资源,避免重复创建对象。
- 提供全局访问点,简化系统配置管理。
2. 工厂模式 vs 抽象工厂模式
题目:
- 比较工厂模式和抽象工厂模式的区别,并举例说明各自的应用场景。
- 编写一个工厂模式的代码示例,模拟不同类型的数据库连接创建。
参考答案:
-
区别:
工厂模式 抽象工厂模式 创建单一产品族的接口(如 Shape
)。创建多个相关产品族的接口(如 Database
和Cache
)。适用于产品种类较少的场景。 适用于需要一组相关对象的场景(如跨平台UI组件)。 -
工厂模式示例:
// 接口 interface Database {void connect(); }// 具体产品 class MySQL implements Database {public void connect() {System.out.println("Connected to MySQL");} }class PostgreSQL implements Database {public void connect() {System.out.println("Connected to PostgreSQL");} }// 工厂类 class DatabaseFactory {public static Database createDatabase(String type) {if (type.equals("MySQL")) return new MySQL();if (type.equals("PostgreSQL")) return new PostgreSQL();throw new IllegalArgumentException("Unknown database type");} }// 使用 public class Main {public static void main(String[] args) {Database db = DatabaseFactory.createDatabase("MySQL");db.connect();} }
-
应用场景:
- 工厂模式: 数据库连接、日志记录器、支付方式(如支付宝、微信)。
- 抽象工厂模式: 跨平台UI框架(如Windows和Mac的按钮、文本框)。
3. 观察者模式
题目:
- 解释观察者模式的定义及其核心组件(主题、观察者),并说明其适用场景。
- 编写一个观察者模式的代码示例,模拟股票价格更新通知。
参考答案:
-
定义:
观察者模式定义对象间的一对多依赖关系,当主题状态变化时,所有依赖者(观察者)自动收到通知并更新。 -
核心组件:
- Subject(主题): 维护观察者列表,提供注册/移除观察者的方法。
- Observer(观察者): 定义更新接口(如
update()
)。
-
代码示例:
// 观察者接口 interface StockObserver {void update(double price); }// 主题 class StockSubject {private List<StockObserver> observers = new ArrayList<>();private double price;public void addObserver(StockObserver observer) {observers.add(observer);}public void removeObserver(StockObserver observer) {observers.remove(observer);}public void setPrice(double price) {this.price = price;notifyObservers();}private void notifyObservers() {for (StockObserver observer : observers) {observer.update(price);}} }// 具体观察者 class Trader implements StockObserver {private String name;public Trader(String name) {this.name = name;}public void update(double price) {System.out.println(name + " received price update: " + price);} }// 使用 public class Main {public static void main(String[] args) {StockSubject stock = new StockSubject();Trader trader1 = new Trader("Alice");Trader trader2 = new Trader("Bob");stock.addObserver(trader1);stock.addObserver(trader2);stock.setPrice(100.5); // 通知所有观察者} }
-
适用场景:
- 事件驱动系统(如GUI事件监听)。
- 实时数据更新(如股票行情、天气预报)。
4. 策略模式
题目:
- 请说明策略模式的核心思想,并描述其与工厂模式的区别。
- 编写一个策略模式的代码示例,模拟不同支付方式(如支付宝、微信、银联)的实现。
参考答案:
-
核心思想:
策略模式将算法封装为独立的类,允许在运行时动态切换策略,避免硬编码条件判断。 -
与工厂模式的区别:
- 策略模式:关注算法替换(如支付方式)。
- 工厂模式:关注对象创建(如创建数据库连接)。
-
代码示例:
// 策略接口 interface PaymentStrategy {void pay(double amount); }// 具体策略 class Alipay implements PaymentStrategy {public void pay(double amount) {System.out.println("Paid " + amount + " via Alipay");} }class WeChatPay implements PaymentStrategy {public void pay(double amount) {System.out.println("Paid " + amount + " via WeChat");} }// 上下文类 class PaymentContext {private PaymentStrategy strategy;public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(double amount) {strategy.pay(amount);} }// 使用 public class Main {public static void main(String[] args) {PaymentContext context = new PaymentContext();context.setStrategy(new Alipay());context.executePayment(100.0);context.setStrategy(new WeChatPay());context.executePayment(50.0);} }
-
适用场景:
- 动态切换算法(如排序策略、折扣计算)。
- 避免冗长的条件判断语句(如支付方式、日志格式)。
5. 装饰器模式
题目:
- 解释装饰器模式的定义,并说明其与继承的区别。
- 编写一个装饰器模式的代码示例,模拟为咖啡添加不同配料(如牛奶、糖)。
参考答案:
-
定义:
装饰器模式通过组合方式动态添加对象功能,避免子类爆炸问题。 -
与继承的区别:
- 继承:静态扩展功能,灵活性差。
- 装饰器:动态组合功能,更灵活且符合开闭原则。
-
代码示例:
// 抽象组件 interface Coffee {double cost();String description(); }// 具体组件 class BlackCoffee implements Coffee {public double cost() { return 2.0; }public String description() { return "Black Coffee"; } }// 装饰器抽象类 abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;} }// 具体装饰器 class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}public double cost() {return decoratedCoffee.cost() + 0.5;}public String description() {return decoratedCoffee.description() + ", Milk";} }class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}public double cost() {return decoratedCoffee.cost() + 0.2;}public String description() {return decoratedCoffee.description() + ", Sugar";} }// 使用 public class Main {public static void main(String[] args) {Coffee coffee = new BlackCoffee();coffee = new MilkDecorator(coffee);coffee = new SugarDecorator(coffee);System.out.println("Cost: " + coffee.cost());System.out.println("Description: " + coffee.description());} }
-
适用场景:
- 动态添加功能(如IO流、文本格式化)。
- 避免类继承层次过深。
6. 责任链模式
题目:
- 请描述责任链模式的核心思想,并举一个实际应用场景。
- 编写一个责任链模式的代码示例,模拟审批流程(如经理、总监、CEO)。
参考答案:
-
核心思想:
将请求的处理责任链式传递,避免请求发送者与处理者直接耦合。 -
应用场景:
- 审批流程(如报销审批、权限校验)。
- 异常处理(如HTTP中间件)。
-
代码示例:
// 处理者接口 abstract class Approver {protected Approver nextApprover;public void setNextApprover(Approver nextApprover) {this.nextApprover = nextApprover;}public abstract void processRequest(double amount); }// 具体处理者 class Manager extends Approver {public void processRequest(double amount) {if (amount <= 1000) {System.out.println("Manager approved: " + amount);} else if (nextApprover != null) {nextApprover.processRequest(amount);}} }class Director extends Approver {public void processRequest(double amount) {if (amount <= 5000) {System.out.println("Director approved: " + amount);} else if (nextApprover != null) {nextApprover.processRequest(amount);}} }class CEO extends Approver {public void processRequest(double amount) {System.out.println("CEO approved: " + amount);} }// 使用 public class Main {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();manager.setNextApprover(director);director.setNextApprover(ceo);manager.processRequest(800); // Managermanager.processRequest(3000); // Directormanager.processRequest(10000); // CEO} }
-
优势:
- 解耦请求发送者和处理者。
- 灵活调整责任链顺序(如增加新审批角色)。
7. 代理模式
题目:
- 解释代理模式的定义,并说明静态代理与动态代理的区别。
- 编写一个代理模式的代码示例,模拟远程服务调用的性能监控。
参考答案:
-
定义:
代理模式为其他对象提供一种代理以控制对这个对象的访问。 -
静态代理 vs 动态代理:
静态代理 动态代理 手动编写代理类。 运行时动态生成代理类(如JDK Proxy)。 适用于固定接口。 适用于任意接口。 -
代码示例:
// 接口 interface Service {void execute(); }// 实现类 class RealService implements Service {public void execute() {System.out.println("Executing service...");try {Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}} }// 代理类 class ServiceProxy implements Service {private Service realService;public ServiceProxy() {this.realService = new RealService();}public void execute() {long startTime = System.currentTimeMillis();realService.execute();long endTime = System.currentTimeMillis();System.out.println("Execution time: " + (endTime - startTime) + "ms");} }// 使用 public class Main {public static void main(String[] args) {Service service = new ServiceProxy();service.execute();} }
-
适用场景:
- 远程调用(如RPC)。
- 权限控制、日志记录、缓存等。
8. 模板方法模式
题目:
- 请描述模板方法模式的核心思想,并编写一个代码示例,模拟不同饮料的制作流程。
参考答案:
-
核心思想:
定义算法骨架,将某些步骤延迟到子类实现,避免代码重复。 -
代码示例:
// 抽象类 abstract class Beverage {// 模板方法(final防止覆盖)public final void prepareRecipe() {boilWater();brew();pourInCup();addCondiments();}// 公共步骤private void boilWater() {System.out.println("Boiling water");}protected abstract void brew();private void pourInCup() {System.out.println("Pouring into cup");}protected abstract void addCondiments();// 钩子方法(可选覆盖)public boolean customerWantsCondiments() {return true;} }// 具体类 class Coffee extends Beverage {protected void brew() {System.out.println("Brewing coffee");}protected void addCondiments() {if (customerWantsCondiments()) {System.out.println("Adding sugar and milk");}}public boolean customerWantsCondiments() {return false; // 用户不想要糖和奶} }class Tea extends Beverage {protected void brew() {System.out.println("Steeping tea");}protected void addCondiments() {System.out.println("Adding lemon");} }// 使用 public class Main {public static void main(String[] args) {Beverage coffee = new Coffee();coffee.prepareRecipe();Beverage tea = new Tea();tea.prepareRecipe();} }
-
适用场景:
- 多步骤算法(如编译器、测试框架)。
- 避免重复代码(如日志记录、事务管理)。
9. 适配器模式
题目:
- 解释适配器模式的定义,并说明其与装饰器模式的区别。
- 编写一个适配器模式的代码示例,模拟旧接口与新接口的兼容。
参考答案:
-
定义:
适配器模式将一个类的接口转换为客户期望的另一个接口,使原本不兼容的类可以协同工作。 -
与装饰器模式的区别:
- 适配器:适配接口(解决兼容性问题)。
- 装饰器:增强功能(不改变接口,仅扩展行为)。
-
代码示例:
// 旧接口 interface OldService {void oldMethod(); }// 新接口 interface NewService {void newMethod(); }// 适配器类 class Adapter implements NewService {private OldService oldService;public Adapter(OldService oldService) {this.oldService = oldService;}public void newMethod() {oldService.oldMethod(); // 适配旧接口} }// 使用 public class Main {public static void main(String[] args) {OldService old = new OldService() {public void oldMethod() {System.out.println("Old method called");}};NewService newService = new Adapter(old);newService.newMethod(); // 输出 "Old method called"} }
-
适用场景:
- 集成第三方库(如旧系统对接新API)。
- 适配遗留代码。
10. 备忘录模式
题目:
- 请描述备忘录模式的定义,并编写一个代码示例,模拟游戏存档功能。
参考答案:
-
定义:
备忘录模式用于保存对象的内部状态,并在需要时恢复状态(撤销/重做)。 -
代码示例:
// 原发器类 class Game {private int level;private int score;public Game(int level, int score) {this.level = level;this.score = score;}public Memento save() {return new Memento(level, score);}public void restore(Memento memento) {this.level = memento.getLevel();this.score = memento.getScore();}public void play() {level++;score += 10;}public void display() {System.out.println("Level: " + level + ", Score: " + score);} }// 备忘录类 class Memento {private final int level;private final int score;public Memento(int level, int score) {this.level = level;this.score = score;}public int getLevel() {return level;}public int getScore() {return score;} }// 使用 public class Main {public static void main(String[] args) {Game game = new Game(1, 0);game.play(); game.display(); // Level 2, Score 10Memento saved = game.save();game.play(); game.display(); // Level 3, Score 20game.restore(saved); game.display(); // 恢复到 Level 2, Score 10} }
-
适用场景:
- 游戏存档、编辑器撤销操作。
- 事务回滚、数据库快照。
总结
以上题目覆盖了Java设计模式的核心知识点,包括创建型、结构型、行为型模式的应用。通过这些问题,可以全面评估候选人对设计模式的理解深度、实际编码能力以及对面向对象设计原则(如开闭原则、单一职责原则)的掌握程度。