2017年7月27日 星期四

[OO 設計模式] Gossip@DesignPattern : Behavioral - Chain of Responsibility 模式

轉載自 這裡 
前言 : 
如果您有一個應用程式,必須對輸入的字元作不同的處理,例如 : 
  1. char c = 'A';  
  2. if (Character.isLetter(c)) {  
  3.    System.out.println("處理字母資料");  
  4. }  
  5. if (Character.isDigit(c)) {  
  6.    System.out.println("處理數字資料");  
  7. }  
  8. System.out.println("處理符號資料");  
使用結構化的方式,用 if..else 來判斷是否應處理,雖然直覺,壞處是如果要調整處理方式,例如要增加或減少處理方式、調整處理順序等,都必須對程式作出修改

Chain of Responsibility 模式 : 
您可以改為以下的方式 : 
- Handler.java : Handler 的抽象類別, 定義介面 API.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Handler {  
  4.     protected Handler next;  
  5.     Handler(Handler next) {  
  6.         this.next = next;  
  7.     }      
  8.     void doNext(char c) {  
  9.         if(next != null) {  
  10.            next.handle(c);  
  11.         }  
  12.     }  
  13.     abstract void handle(char c);  
  14. }  

- SymbolHandler.java : 處理 Symbol 的 Handler.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class SymbolHandler extends Handler {  
  4.     SymbolHandler(Handler next) {  
  5.         super(next);  
  6.     }  
  7.     void handle(char c) {  
  8.         System.out.printf("(%c)Symbol has been handled!\n", c);  
  9.         doNext(c);  
  10.     }  
  11. }  

- CharacterHandler.java : 處理 Char 的 Handler
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class CharacterHandler extends Handler {  
  4.     CharacterHandler(Handler next) {  
  5.         super(next);  
  6.     }      
  7.     void handle(char c) {  
  8.         if(Character.isLetter(c)) {  
  9.             System.out.printf("\t(%c)Character has been handled!\n", c);   
  10.         }  
  11.         doNext(c);  
  12.     }  
  13. }  

- DigitHandler.java : 處理數字的 Handler
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class DigitHandler extends Handler {  
  4.     DigitHandler(Handler next) {  
  5.         super(next);  
  6.     }      
  7.     void handle(char c) {   
  8.        if(Character.isDigit(c)) {  
  9.             System.out.printf("\t(%c)Digit has been handled!\n", c);   
  10.        }  
  11.        doNext(c);  
  12.     }  
  13. }  

- Main.java : 測試主類別
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class Main {  
  4.     public static void main(String[] args) {  
  5.         Handler handler = new SymbolHandler(  
  6.                             new CharacterHandler(  
  7.                               new DigitHandler(null)));  
  8.         handler.handle('A');  
  9.         handler.handle('1');  
  10.     }  
  11. }  

執行結果 : 
(A)Symbol has been handled!
(A)Character has been handled!
(1)Symbol has been handled!
(1)Digit has been handled!

在上例中,在每個特定處理器物件處理過後,可以決定是否交給下一個物件作處理(如果有的話),您可以自由設定下一個處理器,調整處理的順序等,而不用修改程式! 這是 Chain of Responsibility 模式的一個例子,多個物件都有機會處理請求,除了可以自由組合處理請求的物件之外,也可以避免請求的發送者與接收者之間的耦合關係,將這些物件組合為一個鏈,並沿著這個鏈傳遞該請求,每個物件都可以處理請求與決定是否傳遞給下一個處理物件. 

在組織物件之間的職責時,通常是從細粒度至粗粒度的方式來組織,從特殊到抽象化,就像程式中將數字視為字元的特殊化,字元又為符號的特殊化. Chain of Responsibility 的 UML 結構圖如下所示 : 
 

在更一般的情況下,可以將請求包裝為一個物件,並提供 getType() 之間的方法,以讓 Chain of Responsibility 中的物件進行比對,例如 : 
- Request.java : 請求物件, 可以將請求包裝於此物件進行傳遞.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Request {  
  4.     private String type;   
  5.   
  6.     Request(String type) { this.type=type; }  
  7.     String getType() { return type; }  
  8.   
  9.     abstract void execute();  
  10. }  

- Handler.java : 新增處理 Request 物件的 API
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Handler {  
  4.     protected Handler next;  
  5.       
  6.     Handler(Handler next) {  
  7.         this.next = next;  
  8.     }  
  9.       
  10.     void doNext(Request request)  
  11.     {  
  12.          if(next != null)   
  13.          {  
  14.                next.handle(request);  
  15.          }  
  16.     }  
  17.     void doNext(char c) {  
  18.         if(next != null)   
  19.         {  
  20.            next.handle(c);  
  21.         }  
  22.     }  
  23.     abstract void handle(Request request);  
  24.     abstract void handle(char c);  
  25. }  

- ConcreteHandler.java : 如果請求的類型是 "concrete" 則執行請求並停止 chain, 否則將該請求傳遞下去.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class ConcreteHandler extends Handler{  
  4.     ConcreteHandler(Handler next) {  
  5.         super(next);  
  6.     }  
  7.   
  8.     @Override  
  9.     void handle(Request request) {  
  10.         if(request.getType().equals("concrete")) {  
  11.             request.execute();  
  12.         }  
  13.         else {  
  14.             doNext(request);  
  15.         }  
  16.     }  
  17.   
  18.     @Override  
  19.     void handle(char c) {  
  20.         doNext(c);  
  21.     }  
  22. }  

在 Gof 的書中所舉的例子為輔助說明系統,在一個介面中希望使用者一定可以得到相關的說明主題,如果子元件有說明的話,就顯示相關說明,否則的話就轉發給 包括它的容器元件或父元件,以保證使用者的輔助說明請求一定可以得到回應. 

Supplement 
Tutorialspoint - Chain of Responsibility Pattern

沒有留言:

張貼留言

[ Py DS ] Ch1 - IPython: Beyond Normal Python

Source From  Here   Keyboard Shortcuts in the IPython Shell   If you spend any amount of time on the computer, you’ve probably found a u...