從文字角度出發,咱們能夠先將關注點放在「鏈」字上,很容易聯想到鏈式結構,舉個生活中常見的例子,擊鼓傳花遊戲就是一個很典型的鏈式結構,全部人造成一條鏈,相互傳遞。而從另外一個角度說,職責鏈就是所謂的多級結構,好比去醫院開具病假條,普通醫生只能開一天的證實,若是須要更多時常,則需將開具職責轉交到上級去,上級醫師只能開三天證實,如需更多時常,則需將職責轉交到他的上級,以此類推,這就是一個職責鏈模式的典型應用。再好比公司請假,根據請假時常的不一樣,須要遞交到的級別也不一樣,這種層級遞進的關係就是一種多級結構。git
職責鏈模式(Chain Of Responsibility),使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。UML結構圖以下:dom
其中,Handler是抽象處理者,定義了一個處理請求的接口;ConcreteHandler是具體處理者,處理它所負責的請求,可訪問它的後繼者,若是可處理該請求就處理,不然就將該請求轉發給它的後繼者。ide
抽象處理者實現了三個職責:性能
1 public abstract class Handler { 2 3 private Handler nextHandler; //下一個處理者 4 5 public final Response handlerMessage(Request request) { 6 Response response = null; 7 8 if(this.getHandlerLevel().equals(request.getRequestLevel())) { //判斷是不是本身的處理級別 9 response = this.echo(request); 10 } else { 11 if(this.nextHandler != null) { //下一處理者不爲空 12 response = this.nextHandler.handlerMessage(request); 13 } else { 14 //沒有適當的處理者,業務自行處理 15 } 16 } 17 18 return response; 19 } 20 21 //設定下一個處理者 22 public void setNext(Handler handler) { 23 this.nextHandler = handler; 24 } 25 26 //每一個處理者的處理等級 27 protected abstract Level getHandlerLevel(); 28 29 //每一個處理者都必須實現的處理任務 30 protected abstract Response echo(Request request); 31 32 }
這裏咱們定義三個具體處理者,以便能組成一條鏈,ConcreteHandlerB及ConcreteHandlerC就再也不贅述了。測試
1 public class ConcreteHandlerA extends Handler { 2 3 @Override 4 protected Level getHandlerLevel() { 5 //設置本身的處理級別 6 return null; 7 } 8 9 @Override 10 protected Response echo(Request request) { 11 //完成處理邏輯 12 return null; 13 } 14 15 }
Level類負責定義請求和處理級別,具體內容需根據業務產生。this
1 public class Level { 2 //定義一個請求和處理等級 3 }
Request類負責封裝請求,具體內容需根據業務產生。spa
1 public class Request { 2 3 //請求的等級 4 public Level getRequestLevel() { 5 return null; 6 } 7 8 }
Response類負責封裝鏈中返回的結果,具體內容需根據業務產生。3d
1 public class Response { 2 //處理者返回的數據 3 }
咱們在場景類或高層模塊中對類進行組裝,並傳遞請求,返回結果。以下對三個具體處理者進行組裝,按照1→2→3的順序,並得出返回結果。調試
1 public class Client { 2 3 public static void main(String[] args) { 4 Handler handler1 = new ConcreteHandlerA(); 5 Handler handler2 = new ConcreteHandlerB(); 6 Handler handler3 = new ConcreteHandlerC(); 7 8 //設置鏈中的階段順序 1->2->3 9 handler1.setNext(handler2); 10 handler2.setNext(handler3); 11 12 //提交請求返回結果 13 Response response = handler1.handlerMessage(new Request()); 14 } 15 16 }
固然這是個未完成的模板,最終結果會由於 request.getRequestLevel() 爲空而拋出異常,具體內容需根據業務邏輯進行編寫。code
咱們就以請假/加薪爲例,實現一個較爲簡單的職責鏈模式。UML圖以下:
經過Manager抽象類管理全部管理者,setSuperior()方法用於定義職責鏈的下一級,即定義當前管理者的上級。
1 public abstract class Manager { 2 3 protected String name; 4 protected Manager superior; //管理者的上級 5 6 public Manager(String name) { 7 this.name = name; 8 } 9 10 //設置管理者的上級 11 public void setSuperior(Manager superior) { 12 this.superior = superior; 13 } 14 15 //申請請求 16 public abstract void handlerRequest(Request request); 17 18 }
經理類以下,只可批准兩天之內的假期,其他請求將繼續申請上級。
1 public class CommonManager extends Manager { 2 3 public CommonManager(String name) { 4 super(name); 5 } 6 7 @Override 8 public void handlerRequest(Request request) { 9 if (request.getRequestType().equals("請假") && request.getNumber() <= 2) { //只能批准兩天內的假期 10 System.out.println(name + ":" + request.getRequestContent() + ",時長:" + request.getNumber() + "天,被批准"); 11 } else { //其他請求申請上級 12 if (superior != null) { 13 superior.handlerRequest(request); 14 } 15 } 16 } 17 18 }
總監類以下,只可批准五天之內的假期,其他請求將繼續申請上級。
1 public class Majordomo extends Manager { 2 3 public Majordomo(String name) { 4 super(name); 5 } 6 7 @Override 8 public void handlerRequest(Request request) { 9 if (request.getRequestType().equals("請假") && request.getNumber() <= 5) { //只能批准五天內的假期 10 System.out.println(name + ":" + request.getRequestContent() + ",時長:" + request.getNumber() + "天,被批准"); 11 } else { //其他請求申請上級 12 if (superior != null) { 13 superior.handlerRequest(request); 14 } 15 } 16 } 17 18 }
總經理類,能夠批准任意時常的假期,而且能夠批准是否加薪。
1 public class GeneralManager extends Manager { 2 3 public GeneralManager(String name) { 4 super(name); 5 } 6 7 @Override 8 public void handlerRequest(Request request) { 9 if (request.getRequestType().equals("請假")) { //能批准任意時長的假期 10 System.out.println(name + ":" + request.getRequestContent() + ",時長:" + request.getNumber() + "天,被批准"); 11 } else if (request.getRequestType().equals("加薪") && request.getNumber() <= 500) { 12 System.out.println(name + ":" + request.getRequestContent() + ",金額:¥" + request.getNumber() + ",被批准"); 13 } else if (request.getRequestType().equals("加薪") && request.getNumber() > 500) { 14 System.out.println(name + ":" + request.getRequestContent() + ",金額:¥" + request.getNumber() + ",再說吧"); 15 } 16 } 17 18 }
1 public class Request { 2 3 private String requestType; //申請類別 4 private String requestContent; //申請內容 5 private int number; //數量 6 7 public String getRequestType() { 8 return requestType; 9 } 10 11 public void setRequestType(String requestType) { 12 this.requestType = requestType; 13 } 14 15 public String getRequestContent() { 16 return requestContent; 17 } 18 19 public void setRequestContent(String requestContent) { 20 this.requestContent = requestContent; 21 } 22 23 public int getNumber() { 24 return number; 25 } 26 27 public void setNumber(int number) { 28 this.number = number; 29 } 30 31 }
下面測試幾組數據。
1 public class Client { 2 3 public static void main(String[] args) { 4 CommonManager commonManager = new CommonManager("尼古拉斯·經理"); 5 Majordomo majordomo = new Majordomo("尼古拉斯·總監"); 6 GeneralManager generalManager = new GeneralManager("尼古拉斯·總經理"); 7 8 //設置上級 9 commonManager.setSuperior(majordomo); 10 majordomo.setSuperior(generalManager); 11 12 Request request = new Request(); 13 request.setRequestType("請假"); 14 request.setRequestContent("adam請假"); 15 request.setNumber(1); 16 commonManager.handlerRequest(request); 17 18 Request request2 = new Request(); 19 request2.setRequestType("請假"); 20 request2.setRequestContent("adam請假"); 21 request2.setNumber(4); 22 commonManager.handlerRequest(request2); 23 24 Request request3 = new Request(); 25 request3.setRequestType("加薪"); 26 request3.setRequestContent("adam請求加薪"); 27 request3.setNumber(500); 28 commonManager.handlerRequest(request3); 29 30 Request request4 = new Request(); 31 request4.setRequestType("加薪"); 32 request4.setRequestContent("adam請求加薪"); 33 request4.setNumber(1000); 34 commonManager.handlerRequest(request4); 35 } 36 37 }
運行結果以下: