《设计模式》-05-GoF模式-行为型模式(上)

概述

行为型模式主要针对类或对象业务行为的设计问题提供解决方案。
软件开发中,为了定义可复用、可扩展的算法或业务行为,开发人员会专门针对类或对象的行为设计代码方案。例如:

  • 模板方法模式是针对算法中某些可扩展的步骤进行设计
  • 命令模式则是将行为以类的方式封装,用于行为的存储或重做等。
  • 责任链模式、仲裁模式、观察者模式等,在一定程度上可以降低代码耦合度,使代码结构更为灵活。

1. 责任链模式(Chain of Responsibility)

指将客户端请求处理的不同职责对象组成请求处理链。

诠释:
客户端只需要将请求交付到该链上,而不需要关心链上含有哪些对象。
请求处理链上的对象收到请求后,执行自身业务职责,并将该请求传递到下一个链节点。由于客户端不需要了解责任链上节点对象的具体类型,大大降低了客户端与请求处理对象之间的耦合度。

1.1 使用场景

(1)动态设定请求处理对象的集合。

链式数据结构是较优的一种选择。相比于数组、树等数据结构,链式数据结构在数据节点的插入或删除操作方面具有更好的性能。

(2)处理请求对象的类型有多个,且请求需要被所有对象处理,但客户端无法显式地指定具体处理对象的类型。

(3)请求处理行为封装在不同类型的对象中,这些对象之间的优先级由业务决定。

1.2 类结构

责任链模式类结构

  • 客户端Client耦合到请求对象抽象类型Handler,因此,Handler具体子类的变化不会影响到Client;
  • Handler定义后继节点successor指向同类型的对象。
  • ConcreteHandlerA或ConcreteHandlerB是请求处理行为的不同实现类,继承Handler。
  • 当Handler对象收到客户端请求后,开始执行自己的业务职责,之后将该请求传递给后继节点。客户端的请求会在责任链上一直被传递到尾节点后返回,或满足特定条件在某中间节点返回。

时序图如下:
在这里插入图片描述

2. 命令模式(Command)

将类的业务行为以对象的方式封装,以便实现行为的参数化、撤销或重做等需求。

2.1 使用场景

(1)需要对目标类对象的行为实现撤销或重做等操作。
(2)将目标类对象的行为作为参数在不同的对象间传递。
(3)需要对目标业务行为及状态进行存储,以便在需要时调用。
(4)在原子操作组成的高级接口上构建系统。

2.2 类结构

在这里插入图片描述

  • Client是客户类,创建ConcreteCommand对象,并将命令对象存储在Invoker中
  • Command接口定义了命令对象的行为,由ConcreteCommand子类实现
  • Receiver封装具体的命令操作
  • Invoker负责存储和管理Command对象,并触发命令行为的执行

时序图:

  • 当客户端Client需要使用具体的命令时,它自己创建该命令对象,并指定命令对应的Receiver对象;
  • 命令对象创建完成后,Client调用Invoker对象存储它;
  • Invoker对象存储命令对象的同时,执行命令对象的行为;
  • 命令对象收到执行请求后,将请求委托给Receiver对象实现业务处理。

在这里插入图片描述

2.3 使用命令模式

如COS系统的购物车模块需要实现菜品添加、删除和撤销操作(添加、删除)的功能。

3. 解释器模式(Interpreter)

用于表达语言语法树和封装语句解释(或运算)行为的对象。

诠释:
解释器模式将语法树上的根节点定义为抽象表达式类型,子节点作为终结表达式或非终结表达式类型。客户端使用解释器对目标表达式进行解释(或运算)时,传入该表达式所依赖的上下文对象,上下文对象中含有解释(或运算)表达式所需的所有信息。

3.1 使用场景

(1)目标语言的语法规则简单。
(2)目标语言程序效率不是设计的主要目标。

3.2 类结构

在这里插入图片描述

  • Client是构造和使用表达式对象的客户类
  • AbstractExpression定义了抽象表达式类型和解释行为
  • TerminalExpression是终结表达式类型
  • NonTerminalExpression是非终结表达式类型
  • Context是表达式解释行为执行所依赖的上下文。

当Client需要对表达式进行运算时:

  • 先使用终结或非终结表达式类构造出目标表达式的聚合对象
  • 再调用该对象的解释行为,并传入指定的上下文
  • 终结表达式对象执行解释行为时,根据上下文返回运算的结果值
  • 非终结表达式对象执行解释行为时,递归地调用其组合元素的解释行为进行值的运算。

时序图
在这里插入图片描述

3.3 使用解释器

  • COS的设计问题
    COS系统为了防止网络攻击,要求客户登录时计算登录界面验证码公式,并填入正确验证码数值。登录页面的验证码公式是中文大写个位数的加法或减法运算。
  • 分析问题
    (1)验证码公式是算术表达式—加法或减法运算,而且是二元运算表达式,由左子表达式和右子表达式组成。
    (2)公式中使用的中文大写数字等语言符号在表达式运算时应按照特定的上下文转换成对应的整型数值。
    (3)验证码公式可以由若干子表达式组成。
  • 解决问题
    (1)设计抽象表达式接口ValueExpression,定义表达式运算方法interpret()。
    (2)设计TerminalExpression类,实现ValueExpression接口,作为终结表达式类型。
    (3)设计NonTerminalExpression类,实现ValueExpression接口,作为非终结表达式类型,定义二元运算的左子表达式域和右子表达式域。
    (4)设计AddExpression和SubExpression类,继承NonTerminalExpression类,分别实现加法和减法表达式的值运算。
    (5)定义ValueContext表达式运算的上下文类,封装中文字符与整型数值的映射表,并向客户类提供符号值查询接口getValue()。
    (6)客户类LoginCodeVerifier构造和使用表达式对象。

4. 迭代器模式(Iterator)

在不暴露聚合体内部表示的情况下,向客户端提供遍历聚合元素的方法。

4.1 使用场景

(1)需要提供目标聚合对象内部元素的遍历接口,但不暴露其内部表示(一般指聚合元素的管理方式或数据结构)。
(2)目标聚合对象向不同的客户端提供不同的内部元素遍历方法。
(3)为不同类型的聚合对象提供统一的内部元素遍历接口。

4.2 类结构

在这里插入图片描述

  • Iterator定义了目标聚合体Aggregate类型对象的内部元素的抽象访问接口first()、next()方法等
  • ConcreteIterator是IteraIterator的实现类,实现具体的访问行为;
  • Aggregate是不同聚合对象的抽象类型,向客户端提供迭代器对象的创建服务createIterator()。
  • ConcreteAggregate子类继承Aggregate,实现聚合元素的内部表示,创建针对自己的迭代器对象。

$\color{#00ff00}{客户端Client使用Iterator对象访问目标聚合体Aggregate内部元素之前,先通过调用Aggregate对象的createIterator()方法创建针对该对象的迭代器,再使用迭代器提供的访问服务对Aggregate类型对象进行访问。

时序图:
在这里插入图片描述

5. 仲裁者模式(Mediator)

封装和协调多个对象之间的耦合交互行为,以减弱这些对象之间的耦合关联。

在这里插入图片描述
在这里插入图片描述

5.1 使用场景

(1)多个对象之间进行有规律地交互,但因交互关系复杂导致代码难以理解或维护。
(2)想要复用多个相互交互的对象中的某一个或多个,但它们之间的复杂交互关系使得复用难以实现。
(3)分布在多个协作类中的行为需要定制实现,但不想以协作类子类的方式设计。

5.2 类结构

在这里插入图片描述

  • Colleague定义了协作类的抽象类型,持有指向仲裁者Mediator对象的引用,具体协作类作为其子类实现,如ConcreteColleagueA、ConcreteColleagueB等
  • Mediator是仲裁者抽象类,仲裁行为的实现由子类ConcreteMediator负责;
  • ConcreteMediator封装和实现ConcreteColleagueA与ConcreteColleagueB之间的协作行为。

所有Colleague对象的交互请求,都是由Mediator对象进行接收与协调,当Mediator对象收到请求interact()时,会根据协作对象之间的交互逻辑,调用目标对象Colleague的服务接口service()进行业务处理。其时序图如下:

在这里插入图片描述

6. 备忘录模式(Memento)

在不破坏目标对象封装特性的基础上,将目标对象内部的状态存储到外部对象中,以备之后恢复状态时使用。

6.1 应用场景

备忘录模式让状态所有者对象来创建备忘对象,在备忘对象中保存其内部的状态;备忘对象只向状态所有者提供状态数据的访问接口。

6.2 类结构

在这里插入图片描述

  • Originator是状态的所有者,负责创建Memento类型对象来存储其内部的私有状态,或使用Memento类型的对象恢复其历史状态
  • Memento对状态数据进行封装和保护,只允许Originator类型的对象访问,
  • CareTaker对象负责在外部保存创建后的Memento类型对象。

当客户端需要对Originator类型的对象的内部状态生成快照时,请求Originator类型的对象创建其内部状态的快照Memento类型对象,客户端将快照对象保存在CareTaker类型的对象中。
当客户端需要恢复Originator类型对象的内部状态至某个历史快照时,需要从CareTaker类型对象中取出含有历史状态的Memento类型的对象,并将其作为参数传入Originator类型对象的状态恢复接口,Originator类型的对象从目标Memento类型对象中

6.3 使用备忘录

COS系统向订单管理员提供订单状态快照和回滚功能。


posted on 2022-06-13 23:28  运维开发玄德公  阅读(12)  评论(0编辑  收藏  举报  来源

导航