您的位置:首页 > 其它

设计模式的艺术之道--职责链模式

2017-12-08 12:01 309 查看

设计模式的艺术之道–职责链模式

声明:本系列为刘伟老师博客内容总结(http://blog.csdn.net/lovelion),博客中有完整的设计模式的相关博文,以及作者的出版书籍推荐

本系列内容思路分析借鉴了刘伟老师的博文内容,同时改用C#代码进行代码的演示和分析(Java资料过多 C#表示默哀).

本系列全部源码均在文末地址给出。

本系列开始讲解行为型模式,关注如何将现有类或对象组织在一起形成更加强大的结构。

行为型模式(Behavioral Pattern)

关注系统中对象之间的交互,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责

不仅仅关注类和对象本身,还重点关注它们之间的相互作用和职责划分

类行为型模式

使用继承关系在几个类之间分配行为,主要通过多态等方式来分配父类与子类的职责

对象行为型模式

使用对象的关联关系来分配行为,主要通过对象关联等方式来分配两个或多个类的职责

11种常见的行为型模式



职责链模式–请求的链式处理

“对二”,“过”,“过”……这声音熟悉吗?你会想到什么?对!纸牌。在类似“斗地主”这样的纸牌游戏中,某人出牌给他的下家,下家看看手中的牌,如果要不起上家的牌则将出牌请求再转发给他的下家,其下家再进行判断。一个循环下来,如果其他人都要不起该牌,则最初的出牌者可以打出新的牌。在这个过程中,牌作为一个请求沿着一条链在传递,每一位纸牌的玩家都可以处理该请求。在设计模式中,我们也有一种专门用于处理这种请求链式传递的模式,它就是本章将要介绍的职责链模式。

1.1定义

-职责链模式 (Chain of Responsibility Pattern):避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。

- 将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理

- 客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上

1.2情景实例

问题描述

- 采购单的分级审批

菜鸟软件公司承接了某企业供应链管理系统的开发任务,其中包含一个采购审批子系统。该企业的采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批,主任可以审批5万元以下(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万元至50万元(不包括50万元)的采购单,50万元及以上的采购单就需要开董事会讨论决定。



初步思路

初始解决方案,在系统中提供一个采购单处理类PurchaseRequestHandler用于统一处理采购单。

初步关键代码

class PurchaseRequestHandler {
//递交采购单给主任
public void sendRequestToDirector(PurchaseRequest request) {
if (request.getAmount() < 50000) {
//主任可审批该采购单
this.handleByDirector(request);
}
else if (request.getAmount() < 100000) {
//副董事长可审批该采购单
this.handleByVicePresident(request);
}
else if (request.getAmount() < 500000) {
//董事长可审批该采购单
this.handleByPresident(request);
}
else {
//董事会可审批该采购单
this.handleByCongress(request);
}
}

//主任审批采购单
public void handleByDirector(PurchaseRequest request) {
//代码省略
}

//副董事长审批采购单
public void handleByVicePresident(PurchaseRequest request) {
//代码省略
}

//董事长审批采购单
public void handleByPresident(PurchaseRequest request) {
//代码省略
}

//董事会审批采购单
public void handleByCongress(PurchaseRequest request) {
//代码省略
}
}


现存缺点(未来变化)

(1)PurchaseRequestHandler类较为庞大,各个级别的审批方法都集中在一个类中,违反了“单一职责原则”,测试和维护难度大

(2)如果需要增加一个新的审批级别或调整任何一级的审批金额和审批细节或者流程(例如将董事长的审批额度改为60万元)时都必须修改源代码,违反了“开闭原则”。

如何改进

引入职责链模式。比如主任、副董事长、董事长和董事会都可以处理采购单,他们可以构成一条处理采购单的链式结构,采购单沿着这条链进行传递,这条链就称为职责链。职责链可以是一条直线、一个环或者一个树形结构。常见的是直线型,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理。

职责链模式结构的核心在于引入了一个抽象处理者。

UML类图



关键实例源代码

namespace CoRSample
{
abstract class Approver
{
protected Approver successor; //定义后继对象
protected string name; //审批者姓名

public Approver(string name)
{
this.name = name;
}

//设置后继者
public void SetSuccessor(Approver successor)
{
this.successor = successor;
}

//抽象请求处理方法
public abstract void ProcessRequest(PurchaseRequest request);
}
class PurchaseRequest
{
private double amount;  //采购金额
private int number;  //采购单编号
private string purpose;  //采购目的

public PurchaseRequest(double amount, int number, string purpose)
{
this.amount = amount;
this.number = number;
this.purpose = purpose;
}

public double Amount
{
get { return amount; }
set { amount = value; }
}

public int Number
{
get { return number; }
set { number = value; }
}

public string Purpose
{
get { return purpose; }
set { purpose = value; }
}
}
//类似身份省略 President  Manager  Director  Congress
class President : Approver
{
public President(string name) : base(name)
{
}

//具体请求处理方法
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount < 500000)
{
Console.WriteLine("董事长{0}审批采购单:{1},金额:{2}元,采购目的:{3}。", this.name, request.Number, request.Amount, request.Purpose);  //处理请求
}
else
{
this.successor.ProcessRequest(request);  //转发请求
}
}
}
class Program
{
static void Main(string[] args)
{
Approver wjzhang, gyang, jguo, meeting;
//
wjzhang = new Director("张无忌");
gyang = new VicePresident("杨过");
jguo = new President("郭靖");
meeting = new Congress("董事会");

//创建职责链
wjzhang.SetSuccessor(gyang);
gyang.SetSuccessor(jguo);
jguo.SetSuccessor(meeting);

//创建采购单
PurchaseRequest pr1 = new PurchaseRequest(45000, 10001, "购买倚天剑");
wjzhang.ProcessRequest(pr1);

PurchaseRequest pr2 = new PurchaseRequest(60000, 10002, "购买《葵花宝典》");
wjzhang.ProcessRequest(pr2);

PurchaseRequest pr3 = new PurchaseRequest(160000, 10003, "购买《金刚经》");
wjzhang.ProcessRequest(pr3);

PurchaseRequest pr4 = new PurchaseRequest(800000, 10004, "购买桃花岛");
wjzhang.ProcessRequest(pr4);

Console.Read();
}
}
}


1.3模式分析

动机和意图

当请求的处理者有多个相关对象,并对象间存在处理优先顺序,具体被哪一个处理者解决,并不能确定的时候?考虑如何避免多情况的判断,减少客户端与处理类之间的耦合关系?

一般结构

职责链模式包含2个角色:

Handler(抽象处理者):对不同的具体处理者的抽象提升归类,包含共有的处理方法,以及对下一个传递者的引用。

ConcreteHandler(具体处理者):在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象

职责链模式UML类图



改进后的优点

使得一个对象无须知道是其他哪一个对象处理其请求

给对象职责的分配带来更多的灵活性

增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可

现存的缺点

不能保证请求一定会被处理(链中没有包含全部情况)

对于比较长的职责链,系统性能将受到一定影响,在进行代码调试时不太方便

如果建链不当,可能会造成循环调用,将导致系统陷入死循环

纯与不纯的职责链模式

(1) 纯的职责链模式

具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的采购单审批实例中应用的是纯的职责链模式。

(2)不纯的职责链模式

允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。逐级传递的投票机制系统。

适用场景

(1) 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定

(2) 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求

实例源代码

GitHub地址

百度云地址:链接: https://pan.baidu.com/s/1o8Qhg1s 密码: hnhj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: