最近,接到一個需求,在數據計算以前,根據需求的具體內容對數據進行過濾,保留下須要計算的那部分。設計模式
對於職場小白沒經驗的我來講,拿到需求,在肯定於什麼位置過濾數據之後,就開始義無反顧地碼代碼!!ide
怎麼碼呢?固然是創建須要過濾的接口及實現類,而後在裏面進行過濾的具體操做。函數
因爲過濾數據的兩部分是對同一內容進行操做,因而在計算數據以前,優化
嗯,調用第一個實現類方法獲得要過濾的內容,循環過濾數據,過濾第一部分;this
再來調用第二個實現類方法獲得要過濾的內容,循環過濾數據,過濾第二部分。spa
到這裏,需求的功能性基本上算是完成了。但這樣的方式好麼?!設計
若是再來第三個第四個相同的過濾操做呢?!接着如上循環麼?!code
明眼人都能看出來這種方式存在了很大的代碼冗餘,效率並非很高,對象
且後一部分的過濾在前一部分的過濾以後,耦合太緊,之後再看到的話確定頭疼。blog
因而,在同事亦師父的林哥的耐心指導下,開始以責任鏈的形式來優化這部分代碼。
1、對責任鏈的理解
責任鏈模式(Chain of Responsibility Pattern)即爲請求建立一個接收者對象的鏈,給與請求類型,將請求發送者與接收者之間進行解耦。請求的處理被每個接收者進行接收並處理,若是能處理則按照接收者的既定規則處理,而後在該責任鏈上層層傳遞。也能夠在每個接收者中持有下一個接收者的引用,若是本身不能處理,則傳給下一個進行處理。
請求由責任鏈上的每一個接收者進行處理,所以,客戶在傳入請求以後,不須要關心接收者的處理細節以及如何傳遞的,這就實現了請求的發送者和請求接收者之間進行了解耦。
(一)大體實現
一、首先建立一個Handler類,其包含對請求進行處理的方法HandlerRequest();
二、對於不一樣的請求處理方式,建立其相應的接收者類,並繼承並重寫Handler父類中的HandlerRequest()方法,以本身的方式進行實現;
三、對於接收者類的傳遞上,是在每一個接收者類中持有下一接收者的引用,這樣處理不了的請求就傳遞給下一個接收者進行處理。
(二)優缺點
優勢:一、首先是責任的分擔。每一個類都只需承擔本身的責任進行處理,若是不能處理就傳遞給下一個對象,明確各種的職責範圍,符合類的最小封裝原則。
二、能夠根據實際場景的須要自由組合處理流程。如需變動,只須要從新分配該對象鏈便可。
三、類與類之間以鬆耦合的方式來傳遞請求,下降了耦合。
缺點: 因爲請求在各個接收者之間進行傳遞,而每一個接收者處理的方式不一樣,可能會影響處理速度。
(三)應用場景
責任鏈既然叫鏈,便是用於鏈式處理的場景中,使得工做流程化、處理過程流程化。
例如:一、Web開發過程當中對請求的各類filter處理,如請求處理和過濾、對Encoding的處理、獲取客戶端IP地址、獲取客戶證書等。(這個是你們最熟悉的部分)
二、JS的冒泡事件。(這個本人沒太過深刻研究,看了下,大體意思是某事件被觸發,如鼠標點擊了一下按鈕,那麼該事件會在該元素的全部祖先當中被觸發,即自下而上的。)
三、多個對象處理一個請求時。
2、我是如何來實現責任鏈的
說完了我的對責任鏈的理解,接下來就經過一個簡單的例子來說解本人是如何實現責任鏈的。
一、定義一個IRule接口,制定請求處理方法的規則,各接收者都將實現該接口並重寫該方法;
1 public interface IRule { 2 3 /** 4 * 對字符串進行處理 5 * @return 6 */ 7 Object handler(); 8 }
二、定義一個RuleChain類,主要包含兩部分,一部分是能接收傳遞進來的請求對象,一部分是對請求進行處理。
這兩個部分保證了在傳遞請求繼續不一樣處理時,能將接收者加入到責任鏈中造成鏈式結構,後續在增長新的相關接收處理者對象時只需實現自身處理並加入到責任鏈中便可;同時每個接收者都重寫了該責任鏈的處理方法,這樣在進行責任鏈處理時,若是是對相同數據進行處理,只須要一個循環來進行驗證便可,避免了代碼的冗餘。
1 public class RuleChain { 2 3 /** 4 * 裝載各個接收者對象的鏈 5 */ 6 private List<IRule> chain; 7 8 public RuleChain() { 9 chain = new ArrayList<>(); 10 } 11 12 public RuleChain addRule(IRule rule) { 13 chain.add(rule); 14 return this; 15 } 16 17 /** 18 * 各個接收者自行處理數據 19 */ 20 public void handler(StringObj stringObj){ 21 for (IRule rule : chain){ 22 stringObj = rule.handler(); 23 } 24 } 25 }
三、接收者的實現方法
這部分主要是實現RuleChain接口並根據自身狀況重寫其請求處理方法。這樣RuleChain能夠統一地進行請求處理,而後輪到該接收者時,就會調用其重寫的請求處理方法進行處理。
1 public class ConcreteHandlerA implements IRule { 2 3 private StringObj str; 4 5 public ConcreteHandlerA(StringObj str){ 6 this.str = str; 7 } 8 9 /** 10 * 該方法在字符串上上添加「ConcreteHandlerA」 11 */ 12 @Override 13 public StringObj handler() { 14 String string=str.getStr()+"ConcreteHandlerA接收者開始處理,"; 15 str.setStr(string); 16 return str; 17 } 18 }
1 public class ConcreteHandlerB implements IRule{ 2 3 private StringObj str; 4 5 public ConcreteHandlerB(StringObj str){ 6 this.str = str; 7 } 8 9 /** 10 * 判斷前面字符串的長度, 11 * @return 12 */ 13 @Override 14 public StringObj handler() { 15 String end = "ConcreteHandlerB處理完畢,責任鏈結束"; 16 String string = ""; 17 if (str.getStr().length() > 10) { 18 string=str.getStr()+ "前面字符串長度爲"+str.getStr().length()+","+end; 19 }else{ 20 string=str.getStr()+ "前面字符串長度不足10,只有"+str.getStr().length()+","+end; 21 } 22 str.setStr(string); 23 return str; 24 } 25 }
四、Main方法驗證明現及輸出結果
1 public class Main { 2 3 public static void main(String[] args) { 4 StringObj stringObj = new StringObj("責任鏈開始,"); 5 RuleChain chain = new RuleChain().addRule(new ConcreteHandlerA(stringObj)).addRule(new ConcreteHandlerB(stringObj)); 6 chain.handler(stringObj); 7 System.out.println(stringObj.getStr()); 8 } 9 } 10 11 ================================================== 12 責任鏈開始,ConcreteHandlerA接收者開始處理,前面字符串長度爲30,ConcreteHandlerB處理完畢,責任鏈結束
3、責任鏈實現的設計模式六大原則體現
如上所示則爲一個簡答的責任鏈的大體實現過程。
一、經過上面的例子咱們能夠看到,每個類只進行本身的那部分處理方式,符合設計模式的單一職責原則,實現了高內聚低耦合的方針;
二、在Main函數中的main方法中,對於RuleChain來講,咱們只需在後續增長各個處理模塊便可,而後在每一個處理模塊中實現自定義處理。在對各個處理模塊的增長來講,咱們只需實現IRule接口,並重寫其handler方法,便可知足需求。這符合設計模式的開閉原則,即對擴展開放,對修改關閉。
三、接收者的各個類都統一實現了專門的IRule接口,而不會去實現沒必要要的其餘接口,符合接口隔離原則;
四、接收者的handler方法都實現了IRule中的方法,IRule負責抽象方法,而具體的實現細節都放在了各個接收者內部進行處理,符合依賴倒置原則;
五、咱們從上述例子中能夠看到,接收者的類與類之間是不存在耦合的,其連接都是依靠RuleChain來進行的,所以符合迪米特法則,類與類之間的耦合性下降。
六、里氏替換原則在這裏暫時不是很明顯。
4、其餘
大體先說到這裏,後續再進行補充。
若有描述不足之處,請指教!