本文目录导读:

我为你整理了一份系统的Java面试设计模式案例指南,涵盖高频考点、核心代码示例和面试话术,助你从容应对。
创建型模式(高频考点)
单例模式(Singleton)- 最常考
适用场景:数据库连接池、配置管理器、线程池
面试重点:懒汉式(线程安全)、饿汉式、双重检查锁(DCL)、静态内部类、枚举
// 双重检查锁(DCL) - 面试最常问
public class Singleton {
// volatile 防止指令重排序
private static volatile Singleton instance;
private Singleton() {
// 私有构造,防止外部实例化
}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查,避免加锁
synchronized (Singleton.class) { // 加锁
if (instance == null) { // 第二次检查,防止重复创建
instance = new Singleton();
}
}
}
return instance;
}
}
// 静态内部类 - 推荐版(懒加载 + 线程安全)
public class Singleton2 {
private Singleton2() {}
private static class Holder {
private static final Singleton2 INSTANCE = new Singleton2();
}
public static Singleton2 getInstance() {
return Holder.INSTANCE;
}
}
// 枚举版 - 最安全(防反射、防序列化攻击)
public enum Singleton3 {
INSTANCE;
private String config = "默认配置";
public String getConfig() {
return config;
}
}
面试话术:
“我们项目中的
RedisConfigManager采用了双检锁单例,用volatile确保多线程下的可见性,同时通过二次判空避免了同步性能损耗,如果是防序列化破坏,我会用枚举实现,因为枚举天然防止反射和反序列化创建新实例。”
工厂方法模式(Factory Method)
适用场景:日志记录器、文件导出器、数据库连接
// 抽象产品
public interface Logger {
void log(String message);
}
// 具体产品
public class ConsoleLogger implements Logger {
public void log(String message) {
System.out.println("控制台日志: " + message);
}
}
public class FileLogger implements Logger {
public void log(String message) {
System.out.println("文件日志: " + message);
}
}
// 抽象工厂
public abstract class LoggerFactory {
public abstract Logger createLogger();
}
// 具体工厂
public class ConsoleLoggerFactory extends LoggerFactory {
public Logger createLogger() {
return new ConsoleLogger();
}
}
public class FileLoggerFactory extends LoggerFactory {
public Logger createLogger() {
return new FileLogger();
}
}
// 使用
public class Application {
public static void main(String[] args) {
LoggerFactory factory = new ConsoleLoggerFactory();
Logger logger = factory.createLogger();
logger.log("工厂模式示例");
}
}
抽象工厂模式(Abstract Factory)
适用场景:跨平台UI组件(Windows/Linux按钮、菜单)
public interface Button { void click(); }
public interface TextBox { void input(); }
// Windows产品族
public class WindowsButton implements Button {
public void click() { System.out.println("Windows按钮点击"); }
}
public class WindowsTextBox implements TextBox {
public void input() { System.out.println("Windows文本框输入"); }
}
// Mac产品族
public class MacButton implements Button {
public void click() { System.out.println("Mac按钮点击"); }
}
public class MacTextBox implements TextBox {
public void input() { System.out.println("Mac文本框输入"); }
}
// 抽象工厂
public interface UIFactory {
Button createButton();
TextBox createTextBox();
}
// 具体工厂
public class WindowsUIFactory implements UIFactory {
public Button createButton() { return new WindowsButton(); }
public TextBox createTextBox() { return new WindowsTextBox(); }
}
public class MacUIFactory implements UIFactory {
public Button createButton() { return new MacButton(); }
public TextBox createTextBox() { return new MacTextBox(); }
}
结构型模式(中高频)
适配器模式(Adapter)
场景:新旧系统接口兼容、第三方SDK适配
// 旧接口
public interface OldPayment {
void pay(double amount);
}
// 新支付方式 - 接口不兼容
public class WeChatPay {
public void payByWeChat(double money) {
System.out.println("微信支付: " + money + "元");
}
}
// 适配器 - 让旧接口兼容新实现
public class PaymentAdapter implements OldPayment {
private WeChatPay weChatPay;
public PaymentAdapter(WeChatPay weChatPay) {
this.weChatPay = weChatPay;
}
@Override
public void pay(double amount) {
weChatPay.payByWeChat(amount); // 转换调用
}
}
// 客户端使用
public class OrderService {
public void checkout(OldPayment payment) {
payment.pay(100.0);
}
public static void main(String[] args) {
OrderService service = new OrderService();
// 通过适配器使用微信支付
service.checkout(new PaymentAdapter(new WeChatPay()));
}
}
代理模式(Proxy)- 高频
应用场景:Spring AOP、延迟加载、权限控制
// 真实接口
public interface Database {
void query(String sql);
}
// 真实对象
public class RealDatabase implements Database {
public void query(String sql) {
System.out.println("执行查询: " + sql);
}
}
// 代理对象 - 增加缓存、权限控制
public class CacheProxy implements Database {
private RealDatabase realDatabase;
private Map<String, String> cache = new HashMap<>();
public void query(String sql) {
// 代理增强逻辑
if (cache.containsKey(sql)) {
System.out.println("从缓存获取: " + cache.get(sql));
return;
}
if (realDatabase == null) {
realDatabase = new RealDatabase();
}
realDatabase.query(sql);
cache.put(sql, "查询结果");
}
}
面试补充:动态代理(JDK Proxy vs CGLIB)也是高频话题,建议熟练掌握,Spring AOP底层正是基于此。
装饰器模式(Decorator)
场景:Java I/O流、Spring事务增强
public interface Coffee {
double cost();
String description();
}
// 基础咖啡
public class Espresso implements Coffee {
public double cost() { return 2.0; }
public String description() { return "浓缩咖啡"; }
}
// 装饰器基类
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
// 具体装饰器 - 牛奶
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
public double cost() { return coffee.cost() + 0.5; }
public String description() { return coffee.description() + "+牛奶"; }
}
// 使用
Coffee coffee = new Espresso();
coffee = new MilkDecorator(coffee); // 动态添加功能
coffee = new SugarDecorator(coffee); // 再叠加糖
行为型模式(高频)
观察者模式(Observer)- 面试必问
场景:微信公众号推送、消息队列、监听器
// 观察者接口
public interface Observer {
void update(String message);
}
// 被观察者(主题)
public class NewsPublisher {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void publishNews(String news) {
this.latestNews = news;
notifyAllObservers();
}
private void notifyAllObservers() {
for (Observer observer : observers) {
observer.update(latestNews);
}
}
}
// 具体观察者
public class User implements Observer {
private String name;
public User(String name) { this.name = name; }
public void update(String message) {
System.out.println(name + "收到通知: " + message);
}
}
// 客户端
NewsPublisher publisher = new NewsPublisher();
publisher.attach(new User("张三"));
publisher.attach(new User("李四"));
publisher.publishNews("发布Java新版本!");
策略模式(Strategy)- 高频
场景:支付方式选择、排序算法切换、优惠活动
// 策略接口
public interface PayStrategy {
void pay(double amount);
}
// 具体策略 - 支付宝
public class AlipayStrategy implements PayStrategy {
public void pay(double amount) {
System.out.println("支付宝支付: " + amount + "元");
}
}
// 具体策略 - 银行转账
public class BankTransferStrategy implements PayStrategy {
public void pay(double amount) {
System.out.println("银行转账: " + amount + "元");
}
}
// 上下文(使用策略的对象)
public class PaymentContext {
private PayStrategy strategy;
public void setStrategy(PayStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
// 使用 - 运行时动态换策略
PaymentContext context = new PaymentContext();
context.setStrategy(new AlipayStrategy());
context.executePayment(100);
context.setStrategy(new BankTransferStrategy());
context.executePayment(200);
面试加分:策略模式 + 工厂模式结合使用,避免客户端直接new具体策略。
模板方法模式(Template Method)
场景:Spring JdbcTemplate、工作流
// 模板 - 定义算法骨架
public abstract class Workflow {
// 固定工作流,子类不能修改
public final void runWorkflow() {
validate();
execute();
hook(); // 钩子方法(可选)
postProcess();
}
protected abstract void validate();
protected abstract void execute();
// 钩子 - 子类可以选择性覆盖
protected void hook() { }
private void postProcess() {
System.out.println("通用后处理");
}
}
// 具体实现
public class OrderFlow extends Workflow {
protected void validate() {
System.out.println("验证订单信息");
}
protected void execute() {
System.out.println("处理订单业务");
}
protected void hook() {
System.out.println("发送订单通知");
}
}
Spring框架中的设计模式(必考)
| 模式 | 在Spring中的应用 | 举例 |
|---|---|---|
| 工厂模式 | BeanFactory/ApplicationContext | getBean() 创建对象 |
| 单例模式 | 默认Bean作用域 | @Scope("singleton") |
| 代理模式 | AOP、声明式事务 | @Transactional 默认使用CGLIB代理 |
| 模板方法 | JdbcTemplate | 操作数据库模板方法 |
| 观察者模式 | 事件驱动机制 | @EventListener |
| 策略模式 | 资源访问、处理器映射 | HandlerMapping |
| 适配器模式 | 对各种Handler适配 | HandlerAdapter |
| 装饰器模式 | BeanWrapper、对Response处理 | HttpHeadResponseDecorator |
面试准备建议
高频追问问题
- 单例模式为什么用
volatile?(禁止指令重排序,防止拿到未初始化对象) - 如何销毁单例?(反射、序列化反序列化会破坏,需重写
readResolve()) - JDK Proxy和CGLIB的区别?(JDK动态代理基于接口,CGLIB基于继承,Spring默认JDK,没有接口自动用CGLIB)
必背代码清单
- ✅ 双检锁单例(手写)
- ✅ JDK动态代理(手写InvocationHandler)
- ✅ 观察者模式的实现
话术技巧
- 回答时先说应用场景,再讲设计思路,最后给核心代码(场景→思路→代码)
- 强调“为什么用”比“怎么用”更重要
- 结合实际项目举例,如:“我在订单系统中使用了策略模式来应对多种支付方式,避免了大量if-else”
这份资料覆盖了面试中80%以上的设计模式考点,建议你挑2-3个模式,结合自己的项目经历准备成3分钟左右的讲解稿,这样面试时能更有底气、表达更流畅,需要我针对某个具体的模式深入讲解,或者帮你准备开题话术,随时告诉我!