Java設計模式中責任鏈模式詳解
編程是一門藝術,大批量的改動顯然是非常丑陋的做法,用心的琢磨寫的代碼讓它變的更美觀。
在現(xiàn)實生活中,一個事件需要經(jīng)過多個對象處理是很常見的場景。例如,采購審批流程、請假流程等。公司員工請假,可批假的領導有部門負責人、副總經(jīng)理、總經(jīng)理等,但每個領導能批準的天數(shù)不同,員工必須根據(jù)需要請假的天數(shù)去找不同的領導簽名,也就是說員工必須記住每個領導的姓名、電話和地址等信息,這無疑增加了難度。
在計算機軟硬件中也有相關例子,如異常處理中,處理程序根據(jù)異常的類型決定自己是否處理該異常;還有 OkHttp的攔截器,這些都可以考慮使用責任鏈模式來實現(xiàn)。
1.責任鏈設計模式的定義
責任鏈(Chain of Responsibility)模式:為了避免請求發(fā)送者與多個請求處理者耦合在一起,于是將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。
2.責任鏈設計模式的優(yōu)點與不足
責任鏈模式是一種對象行為型模式其主要優(yōu)點:
- 降低了對象之間的耦合度。該模式使得一個對象無須知道到底是哪一個對象處理其請求以及鏈的結構,發(fā)送者和接收者也無須擁有對方的明確信息。
- 增強了系統(tǒng)的可擴展性。可以根據(jù)需要增加新的請求處理類,滿足開閉原則。
- 增強了給對象指派職責的靈活性。當工作流程發(fā)生變化,可以動態(tài)地改變鏈內(nèi)的成員或者調(diào)動它們的次序,也可動態(tài)地新增或者刪除責任。
- 責任鏈簡化了對象之間的連接。每個對象只需保持一個指向其后繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句。
- 責任分擔。每個類只需要處理自己該處理的工作,不該處理的傳遞給下一個對象完成,明確各類的責任范圍,符合類的單一職責原則。
其主要不足:
- 不能保證每個請求一定被處理。由于一個請求沒有明確的接收者,所以不能保證它一定會被處理,該請求可能一直傳到鏈的末端都得不到處理。
- 對比較長的職責鏈,請求的處理可能涉及多個處理對象,系統(tǒng)性能將受到一定影響。
- 職責鏈建立的合理性要靠客戶端來保證,增加了客戶端的復雜性,可能會由于職責鏈的錯誤設置而導致系統(tǒng)出錯,如可能會造成循環(huán)調(diào)用。
3.責任鏈設計模式的實現(xiàn)思路
通常情況下,可以通過數(shù)據(jù)鏈表來實現(xiàn)職責鏈模式的數(shù)據(jù)結構
職責鏈模式主要包含以下角色:
- 抽象處理者(Handler)角色:定義一個處理請求的接口,包含抽象處理方法和一個后繼連接。
- 具體處理者(Concrete Handler)角色:實現(xiàn)抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉給它的后繼者。
- 客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關心處理細節(jié)和請求的傳遞過程。
責任鏈模式的本質是解耦請求與處理,讓請求在處理鏈中能進行傳遞與被處理;理解責任鏈模式應當理解其模式,而不是其具體實現(xiàn)。責任鏈模式的獨到之處是將其節(jié)點處理者組合成了鏈式結構,并允許節(jié)點自身決定是否進行請求處理或轉發(fā),相當于讓請求流動起來。
4.責任鏈設計模式應用實例
場景描述:購買商品打折:假如打折可以疊加,只要符合要求,各種折扣都可以疊加使用。
/** * 責任鏈實現(xiàn)的關鍵是 定義一個next節(jié)點 然后構建一個鏈式結構 */ public abstract class MultyDiscount implements Discount { /** * 鏈的下一個節(jié)點 */ protected MultyDiscount nextMultyDiscount; /** * 通過構造函數(shù) 將下一個節(jié)點鏈接起來 * @param nextMultyDiscount */ public MultyDiscount(MultyDiscount nextMultyDiscount){ this.nextMultyDiscount = nextMultyDiscount; } @Override public int calculate(int money) { if (nextMultyDiscount!=null){ this.nextMultyDiscount.calculate(money); } return money; } } public class FullMultyDiscount extends MultyDiscount{ /** * 通過構造函數(shù) 將下一個節(jié)點鏈接起來 * * @param nextMultyDiscount */ public FullMultyDiscount(MultyDiscount nextMultyDiscount) { super(nextMultyDiscount); } @Override public int calculate(int money) { /*先執(zhí)行滿減操作*/ if (money > 200){ System.out.println("優(yōu)惠滿減20元"); money = money - 20; } /*父類的方法執(zhí)行的是成員變量的優(yōu)惠方案,也就是節(jié)點的優(yōu)惠方案*/ return super.calculate(money); } } /** * 假日一律減5元 */ public class HolidayMultyDiscount extends MultyDiscount { /** * 公共的下一個節(jié)點 存放在父類節(jié)點上 * @param nextMultyDiscount */ public HolidayMultyDiscount(MultyDiscount nextMultyDiscount) { super(nextMultyDiscount); } @Override public int calculate(int money) { if (money > 20){ System.out.println("假日一律減5元"); money = money - 5; } return super.calculate(money); } } /** * 首次購 花費多100元 減免30 */ public class NewerMultyDiscount extends MultyDiscount { public NewerMultyDiscount(MultyDiscount nextMultyDiscount) { super(nextMultyDiscount); } @Override public int calculate(int money) { if (money > 100){ System.out.println("首次購買減30元"); money = money - 30; } return super.calculate(money); } } /** * 第二單8折優(yōu)惠 */ public class SecondMultyDiscount extends MultyDiscount { public SecondMultyDiscount(MultyDiscount nextMultyDiscount) { super(nextMultyDiscount); } @Override public int calculate(int money) { System.out.println("第二單打8折"); Double balance = money * 0.8; return super.calculate(balance.intValue()); } } public class ChainCartClient { /*初始化滿減優(yōu)惠券 滿減沒有下一個節(jié)點 是最后一個節(jié)點*/ private static MultyDiscount multyDiscount = new FullMultyDiscount(null); static { /*新用戶減免優(yōu)惠是 滿減優(yōu)惠*/ multyDiscount = new NewerMultyDiscount(multyDiscount); /*第二單打折扣的下一個節(jié)點是新用戶減免*/ multyDiscount = new SecondMultyDiscount(multyDiscount); /*假日的下一個節(jié)點是 第二單打折扣*/ multyDiscount = new HolidayMultyDiscount(multyDiscount); } public static void main(String[] args) { List<Fruit> products = new ArrayList(); products.add(StaticFactory.getFruitApple()); products.add(StaticFactory.getFruitBanana()); products.add(StaticFactory.getFruitOrange()); ShoppingCart cart = new OtherPayShopping(products); /*注入優(yōu)惠方案*/ cart.setDiscount(multyDiscount); cart.submitOrder(); } }
責任鏈設計模式這個實例中,兩個關鍵點:一個是需要一個成員變量存儲下一個節(jié)點,第二個就是建立一個鏈式結構的數(shù)據(jù)。
5.責任鏈設計模式應用場景
責任鏈模式通常在以下幾種情況使用:
多個對象可以處理一個請求,但具體由哪個對象處理該請求在運行時自動確定。可動態(tài)指定一組對象處理請求,或添加新的處理者。需要在不明確指定請求處理者的情況下,向多個處理者中的一個提交請求。
到此這篇關于Java設計模式中責任鏈模式詳解的文章就介紹到這了,更多相關Java責任鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決spring中redistemplate不能用通配符keys查出相應Key的問題
這篇文章主要介紹了解決spring中redistemplate不能用通配符keys查出相應Key的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11