架构师学习-设计模式

架构师学习 第3篇

设计模式 (Design Patterns)

  • 核心概念与原则

    • 定义:一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
    • 目的:提高代码的可重用性,使代码更容易被他人理解,保证代码可靠性。
    • 核心原则
      • 针对接口编程:客户无须知道对象的特定类型,只需知道对象有客户所期望的接口。
      • 优先使用对象组合:优先使用对象组合(黑箱复用),而不是类继承(白箱复用)。
    • MVC模式案例:Smalltalk中的MVC(模型/视图/控制器)体现了观察者、组合和策略模式的综合应用。
  • 一、创建型模式 (Creational Patterns)

    • 关注点:对象的创建过程,将对象的创建与使用分离。
    • 1. 工厂模式 (Factory)
      • **简单工厂 (Simple Factory)**:(非GoF标准,但常用) 定义一个用于创建对象的接口,由工厂类决定创建哪一种产品实例(如“司机开车”的例子)。
      • **工厂方法 (Factory Method)**:定义创建对象的接口,让子类决定实例化哪一个类。使实例化延迟到子类。
      • **抽象工厂 (Abstract Factory)**:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
    • 2. 单例模式 (Singleton)
      • 定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
      • 实现方式
        • 饿汉式:类加载时初始化。
        • 懒汉式:第一次使用时初始化(需注意线程同步)。
        • 注册表方式:通过HashMap维护实例。
    • 3. 建造者模式 (Builder)
      • 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
      • 角色:指导者 (Director)、抽象建造者 (Builder)、具体建造者 (ConcreteBuilder)、产品 (Product)。
    • 4. 原型模式 (Prototype)
      • 定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
      • 特点:利用Java的clone()方法,分为深克隆和浅克隆。
  • 二、结构型模式 (Structural Patterns)

    • 关注点:类或对象的组合,形成更大的结构。
    • 1. 适配器模式 (Adapter)
      • 定义:将一个类的接口转换成客户希望的另外一个接口,解决接口不兼容问题。
      • 分类:类适配器(继承)、对象适配器(组合)。
    • 2. 桥接模式 (Bridge)
      • 定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
      • 应用:如Java AWT框架,将组件与其在不同操作系统下的实现分离。
    • 3. 组合模式 (Composite)
      • 定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。
      • 应用:文件系统、JUnit中的TestCase与TestSuite。
    • 4. 装饰模式 (Decorator)
      • 定义:动态地给一个对象添加一些额外的职责。比生成子类更为灵活。
      • 特点:透明围栏,客户分不出组件和装饰后的组件的区别。
    • 5. 外观/门面模式 (Facade)
      • 定义:为子系统中的一组接口提供一个一致的界面,定义高层接口使子系统更易使用。
      • 目的:降低客户与子系统之间的耦合。
    • 6. 享元模式 (Flyweight)
      • 定义:运用共享技术有效地支持大量细粒度的对象。
      • 关键:区分内蕴状态(共享)和外蕴状态(不共享)。
    • 7. 代理模式 (Proxy)
      • 定义:为其他对象提供一种代理以控制对这个对象的访问。
      • 类型:远程代理、虚拟代理、保护代理、智能引用等。
  • 三、行为型模式 (Behavioral Patterns)

    • 关注点:对象间的交互和职责分配。
    • 1. 责任链模式 (Chain of Responsibility)
      • 定义:使多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理它。
    • 2. 命令模式 (Command)
      • 定义:将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;支持排队、日志和撤销操作。
    • 3. 解释器模式 (Interpreter)
      • 定义:给定一个语言,定义它的文法表示,并定义一个解释器来解释语言中的句子。
    • 4. 迭代器模式 (Iterator)
      • 定义:提供一种方法顺序访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
    • 5. 中介者/调停者模式 (Mediator)
      • 定义:用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用。
    • 6. 备忘录模式 (Memento)
      • 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
    • 7. 观察者模式 (Observer)
      • 定义:定义对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖者都得到通知并自动更新。
      • 模型:推模型(广播详情) vs 拉模型(观察者主动获取)。
    • 8. 状态模式 (State)
      • 定义:允许一个对象在其内部状态改变时改变它的行为。
      • 对比:与策略模式结构相似,但意图不同(状态是内在变化,策略是外部选择)。
    • 9. 策略模式 (Strategy)
      • 定义:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。
    • 10. 模板方法模式 (Template Method)
      • 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
    • 11. 访问者模式 (Visitor)
      • 定义:表示一个作用于某对象结构中的各元素的操作,使你可以在不改变各元素的类的前提下定义新操作。
      • 机制:依赖于“双重分派”技术。

常用的设计模式(10个)

一、 创建型模式 (Creational Patterns)

这类模式主要关注对象的创建过程,旨在将对象的创建与使用分离。

1. 单例模式 (Singleton)

  • 概念:保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常用于代表系统中本质上唯一的组件。
  • 示例
    • 系统资源管理:如文件系统、打印机假脱机程序或窗口管理器,在系统中通常只应有一个实例存在。
    • 代码实现:可以通过私有化构造函数,并提供一个静态方法(如 getInstance)来返回唯一的实例(可以是饿汉式或懒汉式实现)。

2. 工厂方法模式 (Factory Method)

  • 概念:定义一个用于创建对象的接口,让子类决定实例化哪一个类。这使得一个类的实例化延迟到其子类。
  • 示例
    • 文档应用框架:一个抽象的 Application 类负责管理文档,但它不知道具体的文档类(如 DrawingDocumentTextDocument)。它定义一个 CreateDocument 的工厂方法,由子类来实现具体的文档创建逻辑。
    • 暴发户坐车:在这个例子中,工厂方法模式用来创建不同品牌的汽车(如奔驰、宝马),不同的司机子类(工厂子类)负责创建对应的汽车实例。

3. 抽象工厂模式 (Abstract Factory)

  • 概念:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。主要用于处理产品族的问题。
  • 示例
    • 多视感标准 UI:支持多种界面风格(如 Motif 和 Presentation Manager)的工具包。定义一个 WidgetFactory 接口,包含创建滚动条、窗口、按钮的操作。具体的子类 MotifWidgetFactory 创建 Motif 风格的组件,而 PMWidgetFactory 创建 PM 风格的组件,客户仅需通过抽象接口与工厂交互。

二、 结构型模式 (Structural Patterns)

这类模式关注类和对象的组合。

4. 适配器模式 (Adapter)

  • 概念:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 示例
    • 绘图编辑器:想要复用一个已有的 TextView 类来显示文本,但它的接口与编辑器期望的 Shape 接口不匹配。可以定义一个 TextShape 类(适配器),它继承 Shape 的接口并持有一个 TextView 的实例,将 Shape 的请求(如 BoundingBox)转换为 TextView 的对应操作(如 GetExtent)。
    • USB 转接口:给只提供 USB 充电口的 MP3 播放器配一个充电器转接头,使其能通过普通电源充电。

5. 装饰模式 (Decorator)

  • 概念:动态地给一个对象添加一些额外的职责。相比生成子类,这种方式更为灵活。
  • 示例
    • 图形界面组件:一个文本显示视图 TextView 缺省没有滚动条。如果需要添加滚动条或边框,无需创建子类,而是将 TextView 放入 ScrollDecoratorBorderDecorator 中。对客户而言,装饰后的对象仍是可视组件,但拥有了新功能。
    • JUnit 测试TestDecorator 可以给测试用例添加额外行为,例如 RepeatedTest 装饰器可以让一个测试用例重复运行多次。

6. 代理模式 (Proxy)

  • 概念:为其他对象提供一种代理以控制对这个对象的访问。代理可以在访问实体前进行预处理或控制。
  • 示例
    • **图片懒加载 (虚代理)**:文档编辑器打开包含大型图片的文档时,为了速度不立即加载图片,而是先创建一个 ImageProxy 替代。只有当用户滚动到该图片需要显示时,代理才真正创建并加载图像对象。
    • **权限控制 (保护代理)**:在论坛系统中,通过代理对象判断用户权限(如注册用户与游客),控制是否允许执行“发帖”等操作。

7. 组合模式 (Composite)

  • 概念:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。
  • 示例
    • 图形系统Picture(组合对象)可以包含 LineRectangle(基本对象)或其他 Picture。用户可以对整个 Picture 调用 Draw 操作,它会自动递归调用所有子部件的 Draw
    • JUnitTestSuite 可以包含多个 TestCase 或其他 TestSuite,运行 TestSuite 时会自动运行其包含的所有测试。

三、 行为型模式 (Behavioral Patterns)

这类模式关注对象间的通信、职责分配和算法封装。

8. 策略模式 (Strategy)

  • 概念:定义一系列算法,把它们封装起来,并且使它们可相互替换。该模式让算法独立于使用它的客户而变化。
  • 示例
    • 文本换行算法:一个文本排版系统可能支持多种换行策略(如简单换行、TeX 优化换行、数组式换行)。将这些算法封装在不同的 Compositor 子类中,排版对象 Composition 可以根据需要动态切换使用的策略。
    • 布局管理器:Java AWT 中的 LayoutManager 接口有多种实现(FlowLayout, GridLayout),容器将布局行为委托给具体的策略对象。

9. 观察者模式 (Observer)

  • 概念:定义对象间的一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 示例
    • 数据与图表:一个电子表格数据对象(目标)可能有多个展示图表(观察者,如柱状图、饼图)。当数据改变时,数据对象通知所有图表,图表自动重绘以反映最新数据。
    • JUnitTestResult 维护一个 TestListener 列表。当测试失败或结束时,它会通知所有注册的监听器(如打印结果的界面)。

10. 模板方法模式 (Template Method)

  • 概念:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
  • 示例
    • 打开文档:抽象类 Application 定义了 OpenDocument 的流程(检查文档、创建对象、读取数据),其中具体的步骤如 DoCreateDocumentDoRead 由子类实现,但整体流程由父类控制。
    • JUnit 测试运行TestCase 类定义了 runBare 方法,依次执行 setUp(初始化)、runTest(运行测试)、tearDown(清理)。用户只需要重写这三个步骤的具体实现,而无需改变执行顺序。

资料

https://refactoringguru.cn/design-patterns
https://design-patterns.readthedocs.io/zh-cn/latest/
https://jueee.github.io/design-patterns/