当前位置: 首页 > news >正文

设计模式面试题(14道含答案)

1. 什么是设计模式?为什么要使用设计模式?

答:
设计模式是软件开发中针对常见问题的可复用解决方案,是对优秀代码设计经验的总结。它不是具体的代码,而是一种思想或模板

使用目的:

  • 提高代码的可重用性、可读性和可维护性
  • 降低模块间的耦合度
  • 增强系统的扩展性与灵活性
  • 帮助开发者快速理解大型框架(如 Spring、MyBatis)的设计思想

2. 设计模式分为哪几类?各有哪些典型模式?

答:
设计模式共23种,分为三类:

  • 创建型(5种):单例、工厂方法、抽象工厂、建造者、原型
  • 结构型(7种):适配器、装饰器、代理、外观、桥接、组合、享元
  • 行为型(11种):策略、模板方法、观察者、责任链、命令、状态、访问者、中介者、备忘录、迭代器、解释器

3. 请手写一个线程安全且支持延迟加载的单例模式。

答:(推荐静态内部类方式)

public class Singleton {private Singleton() {}private static class Holder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return Holder.INSTANCE;}
}

✅ 优点:线程安全、延迟加载、简洁高效、利用 JVM 类加载机制保证唯一性。


4. 单例模式如何防止反射攻击?

答:
在构造方法中添加校验标志:

public class Singleton {private static boolean initialized = false;private Singleton() {synchronized (Singleton.class) {if (initialized) {throw new RuntimeException("单例已被实例化,禁止反射创建!");}initialized = true;}}// ... 其他实现(如静态内部类)
}

⚠️ 注意:枚举单例天然防反射,是最安全的方式。


5. 工厂模式有哪几种?它们的区别是什么?

答:

类型特点缺点
简单工厂一个工厂类通过参数创建不同产品违反开闭原则,新增产品需修改工厂
工厂方法每个产品对应一个工厂子类类数量增多,但符合开闭原则
抽象工厂创建产品族(多个相关产品)难以支持新产品的增加(需修改接口)

✅ Spring 的 BeanFactory 是简单工厂 + 反射的典型应用。


6. JDK 动态代理和 CGLIB 代理有什么区别?

答:

对比项JDK 动态代理CGLIB 代理
实现方式基于接口,使用 Proxy 类基于继承,生成目标类的子类
是否需要接口必须有接口不需要接口
能否代理 final 类/方法可以(只要实现接口)❌ 不能代理 final 类或方法
性能较快(JDK 优化好)略慢(需生成字节码)
依赖JDK 自带需引入 cglib 或 spring-core

✅ Spring AOP 默认:有接口 → JDK 代理;无接口 → CGLIB。


7. 什么场景下使用建造者模式?它和工厂模式有何区别?

答:
适用场景:

  • 对象构造参数多(≥4)
  • 参数中有可选字段
  • 对象内部属性存在依赖或约束

与工厂模式区别:

  • 工厂模式:关注“创建什么对象”(产品种类)
  • 建造者模式:关注“如何一步步构建复杂对象”(构建过程)

🌰 例子:StringBuilderOkHttpClient.Builder、订单创建(含地址、商品、优惠券等)


8. 模板方法模式的核心思想是什么?请举例说明。

答:
核心思想:在父类中定义算法骨架(固定流程),将可变步骤延迟到子类实现。

例子:

  • Servlet 中的 service() 调用 doGet() / doPost()
  • JUnit 测试生命周期:setUp() → testXxx() → tearDown()
  • 数据库操作模板:连接 → 执行 SQL → 处理结果 → 关闭连接
abstract class DataProcessor {public final void process() { // 模板方法(final 防止被覆盖)connect();processData(); // 子类实现disconnect();}abstract void processData();
}

9. 策略模式解决了什么问题?如何避免大量 if-else?

答:
解决的问题:将一组可互换的算法封装起来,使它们可以相互替换,消除复杂的条件判断。

实现方式:

  1. 定义策略接口
  2. 每种算法实现一个策略类
  3. 上下文(Context)持有策略并调用
// 支付策略
interface PaymentStrategy { void pay(double amount); }
class WechatPay implements PaymentStrategy { ... }
class Alipay implements PaymentStrategy { ... }// 使用
PaymentContext ctx = new PaymentContext(new WechatPay());
ctx.execute(100);

✅ 避免了 if(type == "wechat") ... else if(type == "alipay") ...


10. 观察者模式的应用场景有哪些?推模式和拉模式有何区别?

答:
应用场景:

  • GUI 事件监听(按钮点击)
  • 消息订阅系统(MQ、EventBus)
  • Spring 事件机制(ApplicationEvent
  • 配置中心动态刷新

推 vs 拉:

  • 推模式:主题主动将完整数据推送给观察者(耦合高,效率高)
  • 拉模式:只通知“有变化”,观察者主动拉取所需数据(解耦好,灵活)

11. 外观模式(门面模式)的作用是什么?请举例。

答:
作用:为复杂的子系统提供一个统一、简化的高层接口,隐藏内部细节。

例子: 用户注册成功后需:

  • 发短信(AliSmsService)
  • 发邮件(EmailService)
  • 推送微信消息(WechatService)

使用外观模式封装为:

public class NotificationFacade {public void sendWelcomeMessage(String user) {sms.send(user);email.send(user);wechat.push(user);}
}

客户端只需调用 sendWelcomeMessage(),无需关心内部调用逻辑。


12. 原型模式中的深拷贝和浅拷贝有什么区别?如何实现深拷贝?

答:

类型行为风险
浅拷贝基本类型复制值,引用类型复制地址修改副本会影响原对象
深拷贝所有对象(包括引用)都新开内存复制完全独立,互不影响

实现深拷贝方式:

  1. 重写 clone() 并递归克隆引用对象(如 list.clone()
  2. 使用序列化/反序列化(推荐,适用于复杂对象)
// 序列化实现深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (User) ois.readObject();

13. Spring 中哪些地方用到了设计模式?

答:

  • 单例模式:默认 Bean 作用域为 singleton
  • 工厂模式BeanFactoryApplicationContext
  • 代理模式:AOP(JDK/CGLIB 动态代理)
  • 模板方法JdbcTemplateRestTemplate
  • 观察者模式ApplicationEvent 事件机制
  • 策略模式ResourceLoader 根据前缀选择不同资源加载策略
  • 适配器模式HandlerAdapter 适配不同 Controller 类型

14. 设计模式的六大原则是什么?请简要说明。

答:(SOLID + LoD)

  1. 单一职责原则(SRP):一个类只负责一个职责
  2. 开闭原则(OCP):对扩展开放,对修改关闭
  3. 里氏替换原则(LSP):子类可替换父类而不影响功能
  4. 接口隔离原则(ISP):接口要小而专,避免臃肿
  5. 依赖倒置原则(DIP):面向接口编程,依赖抽象而非具体
  6. 迪米特法则(LoD):最少知道原则,降低类间耦合

✅ 这些原则是设计模式的理论基础,也是高质量 OOP 设计的核心准则。

 

http://www.dtcms.com/a/609533.html

相关文章:

  • [智能体设计模式] 第9章 :学习与适应
  • 肇庆市建设局网站西双版纳建设厅网站
  • LingJing(灵境)桌面级靶场平台新增:真实入侵复刻,知攻善防实验室-Linux应急响应靶机2,通关挑战
  • 融合尺度感知注意力、多模态提示学习与融合适配器的RGBT跟踪
  • 基于脚手架微服务的视频点播系统-脚手架开发部分Fast-dfs,redis++,odb的简单使用与二次封装
  • 构建高可用Redis:哨兵模式深度解析与Nacos微服务适配实践
  • Linux -- 线程同步、POSIX信号量与生产者消费者模型
  • 微服务重要知识点
  • 东莞seo建站排名昆山有名的网站建设公司
  • 主从服务器
  • Linux 文件缓冲区
  • Node.js中常见的事件类型
  • Nacos的三层缓存是什么
  • 交通事故自动识别_YOLO11分割_DRB实现
  • 用flex做的网站空间注册网站
  • Vue + Axios + Node.js(Express)如何实现无感刷新Token?
  • 重大更新!Ubuntu Pro 现提供长达 15 年的安全支持
  • 重庆做学校网站公司农村服务建设有限公司网站
  • 尝试本地部署 Stable Diffusion
  • 网站前置审批专项好的用户体验网站
  • 【动规】背包问题
  • js:网页屏幕尺寸小于768时,切换到移动端页面
  • 《LLM零开销抽象与插件化扩展指南》
  • C++_面试题_21_字符串操作
  • 多重组合问题与矩阵配额问题
  • 什么情况下会把 SYN 包丢弃?
  • EG27324 带关断功能双路MOS驱动芯片技术解析
  • do_action wordpress 模板关键词优化排名的步骤
  • 海外网站入口通信管理局 网站备案
  • 在 Java 中实现 Excel 数字与文本转换