设计模式是面向对象软件设计的经验与最佳实践,是衡量开发者设计能力与工程素养的重要标尺。在面试中,设计模式相关问题是高频考点,旨在考察候选人的抽象思维、代码设计功底以及对常见问题的解决方案储备。本文将梳理面试中必背的核心设计模式题目,并提供深度解析,助你系统备战。
一、 创建型模式
- 单例模式 (Singleton)
- 必考题:如何实现一个线程安全的单例?请写出至少两种方式(如懒汉式双重检查锁、静态内部类、枚举)。
- 深度解析:面试官不仅期望看到代码,更关注你对延迟加载、线程安全、序列化破坏、反射攻击等细节的理解。需清晰阐述各种实现方式的优缺点及适用场景。
- 工厂方法模式 (Factory Method) 与 抽象工厂模式 (Abstract Factory)
- 必考题:请说明工厂方法模式和抽象工厂模式的区别与联系?
- 深度解析:工厂方法关注产品等级结构(单一产品族的创建),通过子类决定实例化哪个具体产品;抽象工厂关注产品族(多个相关产品系列的创建),提供一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类。能结合UML类图说明则更具说服力。
- 建造者模式 (Builder)
- 必考题:建造者模式与工厂模式有何不同?在什么场景下应该使用建造者模式?
- 深度解析:需突出建造者模式适用于创建复杂对象,且对象的构建过程需要稳定的算法,但各部分的具体实现可以灵活变化的场景。与工厂模式相比,建造者更关注对象的组装过程和步骤,能返回一个组装完成的完整对象。
二、 结构型模式
- 适配器模式 (Adapter)
- 必考题:请描述类适配器与对象适配器的区别,并说明各自的优缺点。
- 深度解析:类适配器采用继承(适配者类),会破坏封装性,且由于Java单继承的限制,不够灵活;对象适配器采用组合(持有适配者对象),更符合合成复用原则,更灵活。需能举例说明(如旧接口升级)。
- 代理模式 (Proxy)
- 必考题:静态代理和动态代理(如JDK动态代理、CGLIB)的原理和区别是什么?
- 深度解析:静态代理在编译期确定代理关系,需为每个被代理类编写代理类,繁琐;JDK动态代理基于接口,利用
InvocationHandler和Proxy类在运行时生成代理类;CGLIB动态代理基于继承,通过生成被代理类的子类来工作。需理解其底层机制(反射、字节码生成)及Spring AOP的代理选择策略。
- 装饰器模式 (Decorator)
- 必考题:装饰器模式与代理模式有何异同?
- 深度解析:两者在结构上相似(都实现相同接口,并持有被包装对象的引用),但意图不同:代理模式侧重于控制访问(如权限验证、延迟加载),装饰器模式侧重于动态地添加功能(如Java I/O流)。代理通常由代理对象决定流程,装饰器通常由客户端组合装饰链。
三、 行为型模式
- 观察者模式 (Observer)
- 必考题:请手写一个观察者模式的简单实现,并说明其在JDK或常见框架(如Spring)中的应用。
- 深度解析:需清晰定义
Subject(主题)和Observer(观察者)接口。重点联系java.util.Observable/Observer(已过时)及java.beans.PropertyChangeSupport/PropertyChangeListener,以及Spring的事件发布/监听机制(ApplicationEvent/ApplicationListener)。
- 策略模式 (Strategy)
- 必考题:策略模式与状态模式在结构和意图上有何区别?
- 深度解析:两者UML类图高度相似,但策略模式的各个策略类之间是平等、平行的关系,客户端主动选择策略,策略之间通常互不影响;状态模式的状态是有状态对象内部的属性,状态转换由状态类自身或上下文管理,是对象行为随状态改变而改变的体现。
- 模板方法模式 (Template Method)
- 必考题:模板方法模式与策略模式都封装算法,它们有什么本质不同?
- 深度解析:模板方法使用继承,在抽象类中定义算法骨架,将具体步骤延迟到子类实现,强调算法步骤的固定性。策略模式使用组合,将整个算法策略封装成独立类,客户端可以灵活替换,强调算法的可互换性。前者是行为由父类控制,后者是行为由客户端控制。
四、 综合与进阶问题
- 设计原则:请阐述SOLID原则(单一职责、开闭原则、里氏替换、接口隔离、依赖倒置)的含义,并举例说明。
- 模式对比:在需要解耦调用者与实现者时,工厂模式、策略模式、命令模式分别如何应用?侧重点有何不同?
- 源码应用:请举例说明JDK、Spring或MyBatis等主流框架/库中使用了哪些设计模式,并简述其作用。
- 场景设计:设计一个缓存模块,需要考虑刷新、过期、多线程访问。你会使用哪些设计模式进行组合设计?
备考建议
- 理解优先于记忆:掌握每种模式的意图、动机、结构(UML)、参与者协作关系,而不仅仅是定义。
- 对比学习:将相似模式(如工厂方法/抽象工厂、代理/装饰器/适配器、策略/状态/模板方法)进行对比,理解其微妙差异。
- 联系实际:多思考在过往项目、开源框架中如何应用这些模式,并能清晰表述。
- 手写代码:对于单例、工厂、观察者、代理等高频模式,务必能写出简洁、正确的代码。
- 阐述权衡:面试中,当被问到“为何用此模式”时,要能说明其带来的好处,同时也能提及可能引入的复杂度等代价。
熟练掌握以上题库与解析,不仅能从容应对面试提问,更能从根本上提升你的软件设计与架构能力,使代码更具可维护性、可扩展性与可复用性。