HIT-SC-Chapter Eleven

HIT-SC-Chapter Eleven

Design Patterns for Reuse and
Maintainability
面向可复用性和可维护性的设计模式


1 Creational patterns

Factory Method pattern

Factory Method

  • Also known as “Virtual Constructor” 虚拟构造器

  • 目的:

    • 为创建对象定义一个接口,让子类决定初始化哪个类
    • 工厂化模式将类初始化延伸至子类。
  • When should we use Factory Method? ---- When a class:

    • 当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
    • 定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类
  • image-20220610155404242

    • 常规情况下,client直接创建具体对象 Product p = new ProductTwo();
    • 在工厂方法模式下:Product p = new ConcreteTwo().makeObject();

    image-20220610155611477

    image-20220610155623750

    • Client需要在程序中直接实例化具体实现类,不是面向接口编程。

    image-20220610155835052

    image-20220610155849724

    • Client使用“工厂方法”来创建实例,得到实例的类型是抽象接口而非具体类

    image-20220610160442185

    • 静态工厂方法既可以在ADT内部实现,也可以构造单独的工厂类

    image-20220610160930702

  • 优点:

    • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体
      创建过程;
    • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对
      原工厂进行任何修改,满足开闭原则;
  • 缺点

    • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加
      了系统的复杂度
  • ???


2 Structural patterns

(1) Adapter

加个“适配器”以便于复用

  • Adapter模式的意图:

    • 将一个类的接口转换成客户希望的另外一个接口。
    • 使原本由于接口不兼容而不能一起工作的类可以一起工作。
    • 适配器模式分为类结构型模式和对象结构型模式两种
      • 前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
  • 优缺点:

    • image-20220610162242204
  • image-20220610162254014

    image-20220610162301690

    image-20220610162307828

    image-20220610162315423

    image-20220610162323930

    image-20220610162331647

    image-20220610162339715

Adapter Pattern 适配器模式

  • 意图:将类的接口转换为客户端期望的另一个接口

  • 将某个类/接口转换为client期望的其他形式

    • 解决类之间接口不兼容的问题
    • 为已有的类提供新的接口
    • 适配器允许由于接口不兼容而无法正常工作的类协同工作
    • 通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。
    • to reuse an old component to a new system
  • 目标:对旧的不兼容组件进行包装,在新系统中使用旧的组件

  • 采用继承或Delegation,加个“适配器”以便于复用

  • image-20220610163114543

  • image-20220610163124886

    image-20220610163217573

    image-20220610163254094

    image-20220610163318402

    image-20220610163327452

    image-20220610163342591

    image-20220610163611008


(2) Decorator

  • 指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
    • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
    • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
  • 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂

装饰模式的结构与实现

  • 通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。

模式的结构

  • 装饰模式主要包含以下角色。
    • –抽象构件(Component)角色:
      • 定义一个抽象接口以规范准备接收附加责任的对象。
    • 具体构件(Concrete Component)角色:
      • 实现抽象构件,通过装饰角色为其添加一些职责。
    • 抽象装饰(Decorator)角色:抽象类
      • 继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
    • 具体装饰(ConcreteDecorator)角色:
      • 实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
    • image-20220610163928707

模式的实现

image-20220610163955794

  • image-20220610164040532


Motivating example of Decorator pattern

  • 问题: 需要对对象进行任意或者动态的扩展组合

  • 方案: 实现一个通用接口作为要扩展的对象,将主要功能委托给基础对象(stack),然后添加功能(undo,secure,..)。

    • 以递归的方式实现
    • 比静态继承更灵活可定制的内聚扩展
    • 装饰器同时使用子类型和委托
  • Component接口定义了操作,或者装饰器可以执行的公共操作

  • ConcreteComponent类是你可以动态添加特性的初始对象。您将首先创建这个对象并向其添加特性

  • Decorator类是一个抽象类,是所有Decorator的父类。虽然它实现了Component接口来定义操作,但它也包含一个受保护的变量Component,该变量指向要装饰的对象。

    • The component variable is simply assigned in the constructor.
    • image-20220610165534406
  • ConcreteDecorator类是能够添加特性的实际装饰类。你可以有任意多的ConcreteDecorator类,每个类都代表一个可以添加的特性。

  • image-20220610165543592

  • image-20220610165648359

    image-20220610165655107

    image-20220610165701639

    image-20220610165713014


Decorator vs. Inheritance

  • Decorator在运行时合成特性
    • 继承在编译时组合特性
  • 装饰器由多个协作对象组成
    • 继承生成一个类型明确的对象
  • 可以混搭多种装饰
    • 多重继承在概念上很困难

Decorators from java.util.Collections

  • Turn a mutable list into an immutable list:
    • static List unmodifiableList(List lst);
    • static Set unmodifiableSet( Set set);
    • static Map<K,V> unmodifiableMap( Map<K,V> map);
  • Similar for synchronization:
    • static List synchronizedList(List lst);
    • static Set synchronizedSet( Set set);
    • static Map<K,V> synchronizedMap( Map<K,V> map);

3 Behavioral patterns

(1) Strategy

整体地替换算法

image-20220610170601494

image-20220610170611506

image-20220610170621923

image-20220610170631158

image-20220610170642278

image-20220610170708023

image-20220610170715575

image-20220610170723344


Strategy Pattern

  • 问题:

    • 对于特定的任务存在不同的算法,但是客户端可以在运行时根据动态上下文在算法之间切换。
  • 示例:对客户列表排序(冒泡排序、合并排序、快速排序)

  • 定义一个算法的接口,每个算法用一个类来实现,客户端针对接口编写程序。

    • 易于扩展的新算法实现
    • 从客户端上下文分离算法
  • 整体地替换算法

  • image-20220610171129126

  • image-20220610171144089

    image-20220610171154931

    image-20220610171206284

    image-20220610171216358


(2) Template Method

模板方法模式

  • Problem:

    • 不同的客户端具有相同的算法步骤,但是每个步骤的具体实现不同。
  • 示例:

    • —执行测试用例的测试套件
    • —打开、读取、写入不同类型的文档
  • Solution:

  • – The common steps of the algorithm are factored out into an abstract class, with abstract (unimplemented) primitive operations representing the customizable parts of the algorithm.在父类中定义通用逻辑和各步骤的抽象方法声明

  • – Subclasses provide different realizations for each of these steps.子类中进行各步骤的具体实现

  • image-20220610171501356

  • image-20220610171511086

    image-20220610171517167

    image-20220610171528410

    image-20220610171537210


模板方法模式适用性

  • 在父类声明一个通用逻辑
  • 模板模式用继承+重写的方式实现算法的不同部分
    • 策略模式用委托机制实现不同完整算法的调用(接口+多态)
  • Template Method is widely used in frameworks

(4) Visitor Pattern

  • 对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类

    • 访问者模式实际做的是创建一个使用其他类中数据的外部类。
    • 如果操作逻辑发生变化,那么我们只需要在visitor实现中进行更改,而不是在所有的item类中进行更改。
  • 本质上:将数据和作用于数据上的某种/些特定操作分离开来。

  • 为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT。

  • image-20220610171828938

  • image-20220610171923503

    image-20220610171930061

    image-20220610171938145


Visitor vs Iterator

  • 迭代器:
    • 以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能delegate到外部的iterator对象。
  • Visitors:
    • 特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT

Strategy vs visitor

  • 二者都是通过delegation建立两个对象的动态联系
    • 但是Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。
    • 而Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。
  • visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作),strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

4 Commonality and Difference of Design Patterns

设计模式的对比:共性样式1

image-20220610172855307

Adaptor

  • 适用场合:你已经有了一个类,但其方法与目前client的需求不一致。
    • 根据OCP原则,不能改这个类,所以扩展一个adaptor和一个统一接口。
  • image-20220610173023931

Template

  • 适用场合:有共性的算法流程,但算法各步骤有不同的实现典型的“将共性提升至超类型,将个性保留在子类型。
  • image-20220610173104459

设计模式的对比:共性样式2

image-20220610173455788

Strategy策略

  • 根据OCP原则,想有多个算法的实现,在右侧树里扩展子类型即可,在左侧子类型里传入不同的类型实例
  • image-20220610200553354

Iterator

  • image-20220610200741526

Factory Method

  • 左右两棵树的子类型一一对应。如果在工厂方法里使用type表征右侧的子类型,那么左侧的子类型只要1个即可。
  • image-20220610200827088

Visitor

  • image-20220610200849039

SUM

image-20220610201037472

posted @   三金同志  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示