设计模式(十三)职责链
一、定義
避免將一個(gè)請求的發(fā)送者與接受者耦合在一起,讓多個(gè)對象都有機(jī)會(huì)接受請求。將接收請求的對象連接成一條鏈,并且沿著這條鏈傳遞請求,直到有一個(gè)對象能夠處理它為止。職責(zé)鏈模式是一種行為型模式
二、描述
職責(zé)鏈可以是一條直線、一個(gè)環(huán)或者一個(gè)樹形結(jié)構(gòu),最常見的職責(zé)鏈?zhǔn)侵本€型,即沿著一條單向的鏈來傳遞請求。包含以下兩個(gè)角色:
1、Handler(抽象處理者):它定義了一個(gè)處理請求的接口,一般設(shè)計(jì)為抽象類,由于不同的具體處理者處理請求的方式不同,因此在其中定義了抽象請求處理方法。每一個(gè)處理者的下家還是一個(gè)處理者,故在抽象處理者中定義了一個(gè)抽象處理者類型的對象(如結(jié)構(gòu)圖中的successor)作為其對下家的引用,通過該引用,處理者可以連成一條鏈。
2、ConcreteHandler(具體處理者):它是抽象處理者的子類,可以處理用戶請求,在具體處理者類中實(shí)現(xiàn)了抽象處理者中定義的抽象請求處理方法,在處理請求之前需要進(jìn)行判斷,看是否有相應(yīng)的處理權(quán)限,如果可以處理請求就處理它,否則則將請求轉(zhuǎn)發(fā)給后繼者;在具體處理者中可以訪問鏈中的下一個(gè)對象,以便請求的轉(zhuǎn)發(fā)。
三、例子
X公司承接了某企業(yè)SCM(Supply Chain Management,供應(yīng)鏈管理)系統(tǒng)的開發(fā)任務(wù),其中包含一個(gè)采購審批子系統(tǒng)。該企業(yè)的采購審批是分級進(jìn)行的,即根據(jù)采購金額的不同由不同層次的主管人員來審批:主任可以審批5萬元以下(不包括5萬)的采購單,副董事長可以審批5萬~10萬(不包括10萬)的采購單,50萬元以及以上的采購單就需要開董事會(huì)討論決定。PurchaseRequest:采購請求類
public class PurchaseRequest
{
// 采購金額
public double Amount { get; set; }
// 采購單編號
public string Number { get; set; }
// 采購目的
public string Purpose { get; set; }
public PurchaseRequest(double amount, string number, string purpose)
{
Amount = amount;
Number = number;
Purpose = purpose;
}
}
Approver:審批者類,充當(dāng)抽象處理者
public abstract class Approver
{
protected Approver successor; // 定義后繼對象
protected string name; // 審批者姓名
public Approver(string name)
{
this.name = name;
}
// 設(shè)置后繼者
public void SetSuccessor(Approver successor)
{
this.successor = successor;
}
// 抽象請求處理方法
public abstract void ProcessRequest(PurchaseRequest request);
}
Director、VicePresident、President、Congress:主管、副總裁、總裁、董事會(huì),充當(dāng)具體處理類
/// <summary>
/// 主管:具體處理類
/// </summary>
public class Director : Approver
{
public Director(string name) : base(name)
{
}
// 具體請求處理方法
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount < 50000)
{
// 處理請求
Console.WriteLine("主管 {0} 審批采購單:{1},金額:{2} 元,采購目的:{3}。",
this.name, request.Number, request.Amount, request.Purpose);
}
else
{
// 如果處理不了,轉(zhuǎn)發(fā)請求給更高層領(lǐng)導(dǎo)
this.successor.ProcessRequest(request);
}
}
}
/// <summary>
/// 副總裁:具體處理類
/// </summary>
public class VicePresident : Approver
{
public VicePresident(string name) : base(name)
{
}
// 具體請求處理方法
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount < 100000)
{
// 處理請求
Console.WriteLine("副總裁 {0} 審批采購單:{1},金額:{2} 元,采購目的:{3}。",
this.name, request.Number, request.Amount, request.Purpose);
}
else
{
// 如果處理不了,轉(zhuǎn)發(fā)請求給更高層領(lǐng)導(dǎo)
this.successor.ProcessRequest(request);
}
}
}
/// <summary>
/// 總裁:具體處理者
/// </summary>
public 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
{
// 如果處理不了,轉(zhuǎn)發(fā)請求給更高層領(lǐng)導(dǎo)
this.successor.ProcessRequest(request);
}
}
}
/// <summary>
/// 董事會(huì):具體處理者
/// </summary>
public class Congress : Approver
{
public Congress(string name) : base(name)
{
}
// 具體請求處理方法
public override void ProcessRequest(PurchaseRequest request)
{
// 處理請求
Console.WriteLine("董事會(huì) {0} 審批采購單:{1},金額:{2} 元,采購目的:{3}。",
this.name, request.Number, request.Amount, request.Purpose);
}
}
Program:客戶端測試類
Approver andy = new Director("Andy");
Approver jacky = new VicePresident("Jacky");
Approver ashin = new President("Ashin");
Approver meeting = new Congress("Congress");
andy.SetSuccessor(jacky);
jacky.SetSuccessor(ashin);
ashin.SetSuccessor(meeting);
// 構(gòu)造采購請求單并發(fā)送審批請求
PurchaseRequest request1 = new PurchaseRequest(45000.00, "MANULIFE201706001", "購買PC和顯示器");
andy.ProcessRequest(request1);
PurchaseRequest request2 = new PurchaseRequest(60000.00, "MANULIFE201706002", "2017開發(fā)團(tuán)隊(duì)活動(dòng)");
andy.ProcessRequest(request2);
PurchaseRequest request3 = new PurchaseRequest(160000.00, "MANULIFE201706003", "2017公司年度旅游");
andy.ProcessRequest(request3);
PurchaseRequest request4 = new PurchaseRequest(800000.00, "MANULIFE201706004", "租用新臨時(shí)辦公樓");
andy.ProcessRequest(request4);
Console.ReadLine();
四、總結(jié)
1、優(yōu)點(diǎn)
(1)使得一個(gè)對象無需知道是其他哪一個(gè)對象處理其請求,僅需知道該請求會(huì)被處理即可,接收者和發(fā)送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結(jié)構(gòu),由客戶端負(fù)責(zé)鏈創(chuàng)建,降低了系統(tǒng)的耦合度。
(2)請求處理對象僅需要維持一個(gè)指向其后繼這的引用,而不需要維持它對所有的候選處理者的引用,可以簡化對象之間的相互連接。
(3)在給對象分配職責(zé)時(shí),職責(zé)鏈可以帶來更多的靈活性,可以通過在運(yùn)行時(shí)對該鏈進(jìn)行動(dòng)態(tài)的增加或修改來增加或改變處理一個(gè)請求的職責(zé)。
(4)在系統(tǒng)中增加一個(gè)新的具體處理者時(shí)無須修改原有系統(tǒng)源代碼,只需要在客戶端重新建立鏈?zhǔn)浇Y(jié)構(gòu)即可,從這一點(diǎn)來看是符合開閉原則的。
2、缺點(diǎn)
(1)由于一個(gè)請求沒有明確的接受者,那么就不能保證它一定會(huì)被處理,該請求可能一直到鏈的末端都得不到處理;一個(gè)請求也可能因職責(zé)鏈沒有被正確配置而得不到處理。
(2)對于比較長的職責(zé)鏈,請求的處理可能涉及多個(gè)處理對象,系統(tǒng)性能有一定影響且不利于調(diào)試。
(3)如果建立鏈不當(dāng),可能會(huì)造成循環(huán)調(diào)用,導(dǎo)致系統(tǒng)進(jìn)入死循環(huán)。
總結(jié)
以上是生活随笔為你收集整理的设计模式(十三)职责链的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 升讯威在线客服系统的并发高性能数据处理技
- 下一篇: 朴素贝叶斯深度解码:从原理到深度学习应用