- [设计模式面试题]blog.csdn.net/weixin_4312…
1、OOP 七大原则
- 开闭原则: 对扩展开放, 对修改关闭
- 里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
- 依赖倒置原则: 要面向接口编程, 不要面向实现编程
- 职责原则: 控制类的粒度大小, 将对象解耦, 提高其内聚性
- 接口隔离原则: 要为各个类建立它们需要的专用接口
- 迪米特法则: 只与你的直接朋友交谈,不跟"陌生人"说话
- 合成复用原则: 尽量先使用组合或者聚合等关联关系实现,其次才考虑使用继承关系来实现
2、主要分类
创建型模式、结构型模式和行为型模式是设计模式的三个主要分类。它们按照不同的目的和应用场景对设计模式进行了划分。
创建型模式(Creational Patterns):创建型模式关注对象的创建方式,并提供了灵活的对象创建机制,以适应不同情况下的对象创建需求。这些模式主要涉及对象的实例化、组合和隐藏创建过程的细节。常见的创建型模式包括单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式。
结构型模式(Structural Patterns):结构型模式关注对象之间的组合和关联方式,以形成更大的结构。这些模式帮助确保各个对象可以协同工作,并通过定义对象之间的接口和关系来简化系统的结构。它们通常用于处理对象的组合、接口转换和对象之间的关联问题。常见的结构型模式包括适配器模式、代理模式、装饰器模式、桥接模式、组合模式、外观模式和享元模式。
行为型模式(Behavioral Patterns):行为型模式关注对象之间的交互和职责分配方式,以支持可维护和可扩展的代码。这些模式涉及算法、职责分配和通信模式等方面,用于定义对象之间的通信方式和交互模式。常见的行为型模式包括策略模式、观察者模式、命令模式、模板方法模式、迭代器模式、状态模式、职责链模式和访问者模式。
这种划分方式有助于开发人员更好地理解各种设计模式的目的和使用场景。不同的模式分类在解决软件设计中的不同问题时有不同的关注点。选择适合的模式取决于具体的设计需求和约束,以及开发团队的经验和技术栈。在实际应用中,也可能会结合多个模式来解决复杂的设计问题。
3、适用场景
Java 设计模式适用场景总结
| 模式类别 | 模式名称 | 核心目的 | 典型适用场景 |
|---|---|---|---|
| 创建型模式 | 单例模式 (Singleton) | 确保一个类只有一个实例,并提供全局访问点。 | 需要严格控制的共享资源(连接池、配置、日志)、只需要一个实例协调行为、创建开销大的对象复用。 |
| 工厂方法模式 (Factory Method) | 定义一个创建对象的接口,让子类决定实例化哪个类。 | 无法预知创建的具体对象类型、需要解耦对象创建与使用、为框架提供扩展点、一组相关类(产品族)在运行时确定。 | |
| 抽象工厂模式 (Abstract Factory) | 提供一个接口创建相关或依赖对象的家族,不指定具体类。 | 需要创建整个产品族(如UI套件、数据库组件)、系统需独立于产品的创建组合、运行时切换整个产品族、产品相互关联必须一起使用。 | |
| 建造者模式 (Builder) | 将一个复杂对象的构建与其表示分离,分步构建。 | 创建包含多个部件的复杂对象、构造过程需分步骤或不同顺序、构造参数多且有可选参数、需要精细控制构造过程。 | |
| 原型模式 (Prototype) | 通过复制现有实例来创建新对象。 | 对象类型在运行时动态指定、避免创建平行的工厂类、直接创建对象成本高(复制更高效)、需要动态加载类或隔离创建。 | |
| 结构型模式 | 适配器模式 (Adapter) | 将一个类的接口转换成客户期望的另一个接口。 | 使用现有类但其接口不兼容、集成第三方库或遗留代码、统一多个不同接口的类、创建与未知接口类协同工作的类。 |
| 桥接模式 (Bridge) | 将抽象部分与实现部分分离,使它们可以独立变化。 | 存在多个维度的变化(如形状+颜色)、不希望抽象与实现固定绑定、抽象和实现都需通过子类扩展、向客户隐藏实现细节。 | |
| 组合模式 (Composite) | 将对象组合成树形结构表示“部分-整体”层次,统一对待。 | 表示“部分-整体”层次结构(文件系统、菜单)、用户需统一使用单个对象和组合对象、需要对树形结构执行递归操作(遍历、计算)。 | |
| 装饰器模式 (Decorator) | 动态地给对象添加额外的职责,比继承更灵活。 | 需动态透明地为单个对象添加职责(不影响其他)、职责可撤销、继承导致子类爆炸或类不可继承、需要组合多个功能(嵌套装饰器)。 | |
| 外观模式 (Facade) | 为子系统中的一组接口提供一个一致的、更高级别的界面。 | 简化复杂子系统的使用接口、解耦客户端与子系统、子系统难以理解时提供统一入口、对子系统分层。 | |
| 享元模式 (Flyweight) | 运用共享技术有效支持大量细粒度对象,减少内存开销。 | 应用使用大量对象造成很大存储开销、对象的大多数状态可变为外部状态(运行时传入)、移除外在状态后可用少量共享对象替代。 | |
| 代理模式 (Proxy) | 为其他对象提供一种代理以控制对这个对象的访问。 | 远程代理(访问远程对象)、虚拟代理(创建开销大的对象代表)、保护代理(控制访问权限)、智能引用(懒加载、日志、计数)、缓存代理。 | |
| 行为型模式 | 责任链模式 (Chain of Responsibility) | 使多个对象有机会处理请求,避免发送者和接收者耦合。 | 多个对象可处理同一请求但运行时确定接收者、不明确指定接收者提交请求、需动态指定处理对象链、按优先级顺序处理(审批、事件)。 |
| 命令模式 (Command) | 将请求封装为对象,支持参数化、排队、日志、撤销操作。 | 解耦请求调用者与接收者、需要支持命令排队、日志记录、撤销/重做、宏命令(组合命令)、将操作作为参数传递(线程池任务)。 | |
| 解释器模式 (Interpreter) | 定义文法表示和解释器,解释特定语言中的句子。 | 需要解释执行特定类型问题(可表示为简单语法)、效率非关键因素、语法相对简单(复杂文法用解析器生成器)。 | |
| 迭代器模式 (Iterator) | 提供一种方法顺序访问聚合对象元素,无需暴露内部表示。 | 需要访问聚合对象内容而不暴露内部结构、需要支持多种遍历方式、需要为不同聚合结构提供统一遍历接口。 | |
| 中介者模式 (Mediator) | 用一个中介对象封装一系列对象交互,降低耦合。 | 对象间存在复杂引用导致网状结构、需要控制中心协调多个对象交互(如GUI控件、MVC Controller)、避免生成过多子类封装行为。 | |
| 备忘录模式 (Memento) | 在不破坏封装的前提下,捕获对象状态并在外部保存,以便恢复。 | 需要保存/恢复对象历史状态、需要提供撤销(Undo)操作、直接获取内部状态会破坏封装性。 | |
| 观察者模式 (Observer) | 定义对象间一对多依赖,一个对象状态改变自动通知更新。 | 一个对象改变需通知多个对象(数量未知)、解耦通知者与被通知者、事件驱动系统、广播通信。 | |
| 状态模式 (State) | 允许对象在其内部状态改变时改变它的行为。 | 对象行为取决于其状态且需在运行时改变行为、操作中含有庞大依赖于状态的多分支条件语句、状态转换规则复杂或状态数量多。 | |
| 策略模式 (Strategy) | 定义一系列算法并封装,使它们可相互替换且独立于客户端。 | 需要在不同情况下使用不同算法或行为、存在多种完成同一任务的方式需运行时选择、隔离算法实现与使用代码、消除条件语句。 | |
| 模板方法模式 (Template Method) | 定义算法骨架,将一些步骤延迟到子类实现。 | 多个类有相同算法流程但某些步骤实现不同、需要控制子类扩展点(钩子)、提取公共行为到父类避免重复、框架设计(定义骨架用户实现步骤)。 | |
| 访问者模式 (Visitor) | 在不改变元素类的前提下定义作用于元素的新操作。 | 对象结构包含多种类型对象需实施类型相关操作、需对结构进行多种不相关操作避免污染元素类、对象结构稳定但经常新增操作、跨越类层次执行操作。 |
选择模式的关键提示:
- 识别问题优先: 明确你要解决的核心问题是什么(创建对象复杂?结构组合不灵活?对象间通信混乱?职责分配不清?)。
- 匹配模式意图: 查看表格中的“核心目的”和“典型适用场景”,找到与你的问题描述最契合的模式。
- 权衡利弊: 每个模式都会增加一定复杂性。评估引入模式带来的好处(解耦、复用、扩展性、可维护性)是否大于其成本(学习曲线、代码量增加、潜在过度设计)。
- 避免教条主义: 不要为了用模式而用模式! 简单的代码通常比过度设计的模式化代码更好。模式是工具箱里的工具,在合适的时候选用合适的工具。