15、设计模式-行为型模式-职责链模式
職責(zé)鏈模式
?
很多情況下,在一個(gè)軟件系統(tǒng)中可以處理某個(gè)請(qǐng)求的對(duì)象不止一個(gè),例如SCM系統(tǒng)中的采購(gòu)
單審批,主任、副董事長(zhǎng)、董事長(zhǎng)和董事會(huì)都可以處理采購(gòu)單,他們可以構(gòu)成一條處理采購(gòu)
單的鏈?zhǔn)浇Y(jié)構(gòu),采購(gòu)單沿著這條鏈進(jìn)行傳遞,這條鏈就稱為職責(zé)鏈。
?
職責(zé)鏈可以是一條直線、一個(gè)環(huán)或者一個(gè)樹(shù)形結(jié)構(gòu),最常見(jiàn)的職責(zé)鏈?zhǔn)侵本€型
即沿著一條單向的鏈來(lái)傳遞請(qǐng)求。
?
鏈上的每一個(gè)對(duì)象都是請(qǐng)求處理者,職責(zé)鏈模式可以將請(qǐng)求的處理者組織成一條鏈,并
讓請(qǐng)求沿著鏈傳遞,由鏈上的處理者對(duì)請(qǐng)求進(jìn)行相應(yīng)的處理,客戶端無(wú)須關(guān)心請(qǐng)求的處理細(xì)
節(jié)以及請(qǐng)求的傳遞,只需將請(qǐng)求發(fā)送到鏈上即可,實(shí)現(xiàn)請(qǐng)求發(fā)送者和請(qǐng)求處理者解耦。
?
定義:
避免請(qǐng)求發(fā)送者與接收者
耦合在一起,讓多個(gè)對(duì)象都有可能接收請(qǐng)求,將這些對(duì)象連接成一條鏈,并且沿著這條鏈傳
遞請(qǐng)求,直到有對(duì)象處理它為止。職責(zé)鏈模式是一種對(duì)象行為型模式
Handler(抽象處理者):它定義了一個(gè)處理請(qǐng)求的接口,一般設(shè)計(jì)為抽象類,由于不同的
具體處理者處理請(qǐng)求的方式不同,因此在其中定義了抽象請(qǐng)求處理方法。因?yàn)槊恳粋€(gè)處理者
的下家還是一個(gè)處理者,因此在抽象處理者中定義了一個(gè)抽象處理者類型的對(duì)象(如結(jié)構(gòu)圖
中的successor),作為其對(duì)下家的引用。通過(guò)該引用,處理者可以連成一條鏈。
?
ConcreteHandler(具體處理者):它是抽象處理者的子類,可以處理用戶請(qǐng)求,在具體處理
者類中實(shí)現(xiàn)了抽象處理者中定義的抽象請(qǐng)求處理方法,在處理請(qǐng)求之前需要進(jìn)行判斷,看是
否有相應(yīng)的處理權(quán)限,如果可以處理請(qǐng)求就處理它,否則將請(qǐng)求轉(zhuǎn)發(fā)給后繼者;在具體處理
者中可以訪問(wèn)鏈中下一個(gè)對(duì)象,以便請(qǐng)求的轉(zhuǎn)發(fā)。
?
?
事例:
?
//請(qǐng)求類:采購(gòu)單 public class PurchaseRequest {private double amount; //采購(gòu)金額private int number; //采購(gòu)單編號(hào)private String purpose; //采購(gòu)目的public PurchaseRequest(double amount, int number, String purpose) {this.amount = amount;this.number = number;this.purpose = purpose;}public double getAmount() {return amount;}public void setAmount(double amount) {this.amount = amount;}public int getNumber() {return number;}public void setNumber(int number) {this.number = number;}public String getPurpose() {return purpose;}public void setPurpose(String purpose) {this.purpose = purpose;} } //抽象處理者 abstract class Approver {protected Approver successor;//定義后繼對(duì)象protected String name;//審批者姓名public Approver(String name){this.name = name;}//設(shè)置后繼者public void setSuccessor(Approver successor) {this.successor = successor;}//抽象請(qǐng)求處理方法public abstract void processRequest(PurchaseRequest request); } //具體處理者 public class Director extends Approver {public Director(String name) {super(name);}@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 50000){System.out.println("主任:"+ this.name + "審批采購(gòu)單:"+ request.getNumber() + ",金額:"+ request.getAmount() + "元,采購(gòu)目的:"+ request.getPurpose() + "。"); //處理請(qǐng)求}else{//轉(zhuǎn)發(fā)請(qǐng)求this.successor.processRequest(request);}} } public class VicePresident extends Approver {public VicePresident(String name) {super(name);}@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 100000){System.out.println("副董事長(zhǎng):"+ this.name + "審批采購(gòu)單:"+ request.getNumber() + ",金額:"+ request.getAmount() + "元,采購(gòu)目的:"+ request.getPurpose() + "。"); //處理請(qǐng)求}else{//轉(zhuǎn)發(fā)請(qǐng)求this.successor.processRequest(request);}} } public class President extends Approver {public President(String name) {super(name);}@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 500000) {System.out.println("董事長(zhǎng)" + this.name + "審批采購(gòu)單:" +request.getNumber() + ",金額:" +request.getAmount() + "元,采購(gòu)目的:" +request.getPurpose() + "。"); //處理請(qǐng)求 }else {this.successor.processRequest(request); //轉(zhuǎn)發(fā)請(qǐng)求 }} }?
//董事會(huì)類:具體處理者 public class Congress extends Approver{public Congress(String name) {super(name);}@Overridepublic void processRequest(PurchaseRequest request) {System.out.println("召開(kāi)董事會(huì)審批采購(gòu)單:"+ request.getNumber() + ",金額:"+ request.getAmount() + "元,采購(gòu)目的:"+ request.getPurpose() + "。"); //處理請(qǐng)求 } }?
public class client {public static void main(String[] args) {Approver wjzhang,gyang,jguo,meeting;wjzhang = new Director("張無(wú)忌");gyang = new VicePresident("楊過(guò)");jguo = new President("郭靖");meeting = new Congress("董事會(huì)");//創(chuàng)建職責(zé)鏈 wjzhang.setSuccessor(gyang);gyang.setSuccessor(jguo);jguo.setSuccessor(meeting);//創(chuàng)建采購(gòu)單PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"購(gòu)買倚天劍");wjzhang.processRequest(pr1);PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"購(gòu)買《葵花寶典》");wjzhang.processRequest(pr2);PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"購(gòu)買《金剛經(jīng)》");wjzhang.processRequest(pr3);PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"購(gòu)買桃花島");wjzhang.processRequest(pr4);} }?
圖構(gòu):
?
?
?
(1) 純的職責(zé)鏈模式
一個(gè)純的職責(zé)鏈模式要求一個(gè)具體處理者對(duì)象只能在兩個(gè)行為中選擇一個(gè):要么承擔(dān)全部責(zé)
任,要么將責(zé)任推給下家,不允許出現(xiàn)某一個(gè)具體處理者對(duì)象在承擔(dān)了一部分或全部責(zé)任后
又將責(zé)任向下傳遞的情況。而且在純的職責(zé)鏈模式中,要求一個(gè)請(qǐng)求必須被某一個(gè)處理者對(duì)
象所接收,不能出現(xiàn)某個(gè)請(qǐng)求未被任何一個(gè)處理者對(duì)象處理的情況。在前面的采購(gòu)單審批實(shí)
例中應(yīng)用的是純的職責(zé)鏈模式。
?
?
(2)不純的職責(zé)鏈模式
在一個(gè)不純的職責(zé)鏈模式中允許某個(gè)請(qǐng)求被一個(gè)具體處理者部分處理后再向下傳遞,或者一
個(gè)具體處理者處理完某請(qǐng)求后其后繼處理者可以繼續(xù)處理該請(qǐng)求,而且一個(gè)請(qǐng)求可以最終不
被任何處理者對(duì)象所接收。Java AWT 1.0中的事件處理模型應(yīng)用的是不純的職責(zé)鏈模式,其基
本原理如下:由于窗口組件(如按鈕、文本框等)一般都位于容器組件中,因此當(dāng)事件發(fā)生
在某一個(gè)組件上時(shí),先通過(guò)組件對(duì)象的handleEvent()方法將事件傳遞給相應(yīng)的事件處理方法,
該事件處理方法將處理此事件,然后決定是否將該事件向上一級(jí)容器組件傳播;上級(jí)容器組
件在接到事件之后可以繼續(xù)處理此事件并決定是否繼續(xù)向上級(jí)容器組件傳播,如此反復(fù),直
到事件到達(dá)頂層容器組件為止;如果一直傳到最頂層容器仍沒(méi)有處理方法,則該事件不予處
理。每一級(jí)組件在接收到事件時(shí),都可以處理此事件,而不論此事件是否在上一級(jí)已得到處
理,還存在事件未被處理的情況。顯然,這就是不純的職責(zé)鏈模式,早期的Java AWT事件模
型(JDK 1.0及更早)中的這種事件處理機(jī)制又叫事件浮升(Event Bubbling)機(jī)制。從Java.1.1以
后,JDK使用觀察者模式代替職責(zé)鏈模式來(lái)處理事件。目前,在JavaScript中仍然可以使用這
種事件浮升機(jī)制來(lái)進(jìn)行事件處理。
?
?優(yōu)點(diǎn):
?
(1) 職責(zé)鏈模式使得一個(gè)對(duì)象無(wú)須知道是其他哪一個(gè)對(duì)象處理其請(qǐng)求,對(duì)象僅需知道該請(qǐng)求會(huì)
被處理即可,接收者和發(fā)送者都沒(méi)有對(duì)方的明確信息,且鏈中的對(duì)象不需要知道鏈的結(jié)構(gòu),
由客戶端負(fù)責(zé)鏈的創(chuàng)建,降低了系統(tǒng)的耦合度。
(2) 請(qǐng)求處理對(duì)象僅需維持一個(gè)指向其后繼者的引用,而不需要維持它對(duì)所有的候選處理者的
引用,可簡(jiǎn)化對(duì)象的相互連接。
?
(3) 在給對(duì)象分派職責(zé)時(shí),職責(zé)鏈可以給我們更多的靈活性,可以通過(guò)在運(yùn)行時(shí)對(duì)該鏈進(jìn)行動(dòng)
態(tài)的增加或修改來(lái)增加或改變處理一個(gè)請(qǐng)求的職責(zé)。
(4) 在系統(tǒng)中增加一個(gè)新的具體請(qǐng)求處理者時(shí)無(wú)須修改原有系統(tǒng)的代碼,只需要在客戶端重新
建鏈即可,從這一點(diǎn)來(lái)看是符合“開(kāi)閉原則”的。
?
?缺點(diǎn):
(1) 由于一個(gè)請(qǐng)求沒(méi)有明確的接收者,那么就不能保證它一定會(huì)被處理,該請(qǐng)求可能一直到鏈
的末端都得不到處理;一個(gè)請(qǐng)求也可能因職責(zé)鏈沒(méi)有被正確配置而得不到處理。
(2) 對(duì)于比較長(zhǎng)的職責(zé)鏈,請(qǐng)求的處理可能涉及到多個(gè)處理對(duì)象,系統(tǒng)性能將受到一定影響,
而且在進(jìn)行代碼調(diào)試時(shí)不太方便。
(3) 如果建鏈不當(dāng),可能會(huì)造成循環(huán)調(diào)用,將導(dǎo)致系統(tǒng)陷入死循環(huán)。
?
?適用場(chǎng)景:
(1) 有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求,具體哪個(gè)對(duì)象處理該請(qǐng)求待運(yùn)行時(shí)刻再確定,客戶端只
需將請(qǐng)求提交到鏈上,而無(wú)須關(guān)心請(qǐng)求的處理對(duì)象是誰(shuí)以及它是如何處理的。
(2) 在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求。
(3) 可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求,客戶端可以動(dòng)態(tài)創(chuàng)建職責(zé)鏈來(lái)處理請(qǐng)求,還可以改變鏈中處理者之間的先后次序。
?
轉(zhuǎn)載于:https://www.cnblogs.com/Mrchengs/p/10897964.html
總結(jié)
以上是生活随笔為你收集整理的15、设计模式-行为型模式-职责链模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: LINQPad工具-linq、sql、I
- 下一篇: Dom4j工具--XML的DOM解析(下