1. 前文彙總
2. 請假
作為一位新時代的社畜,我們每天起得比雞早,睡得比狗晚,還時不時的要受到上司的 PUA ,每天都生活在水深火熱之中。
生活中總會有各種意外,比如生病了,需要去醫院看病,那我們需要請假去醫院,一般在公司中,請假的時長和審批領導息息相關,如果這個規則是這樣的:
- 請假 3 天內小組長可以審批
- 請假 5 天內需要大組長神品
- 請假 20 天內需要部門經理審批
如果按照順序思維來寫程式的話,那麼我們需要做大量的 if...else 的判斷,並且所有的類都要耦合在一起,這時,我們可以使用責任鏈模式,上面的審批流成如下:
我們可以先定義一個員工類:
public interface IPerson {
// 獲取當前請假天數
int getDays();
// 獲取審批結果
String getResult();
}
public class Person implements IPerson {
private int days;
private String message;
public Person(int days) {
this.days = days;
this.message = "領導,我想請 " + days + " 天假!!!";
}
@Override
public int getDays() {
return this.days;
}
@Override
public String getResult() {
return this.message;
}
}
建立一個抽象 Handler 類:
public abstract class Handler {
public final static int MIN = 3;
public final static int MIDDLE = 5;
public final static int MAX = 20;
// 當前能處理的級別
private int days;
// 責任傳遞,定義下一個責任人
private Handler nextHandler;
// 所有的類都需要定義自己的能處理的請假天數
public Handler(int days) {
this.days = days;
}
public final void handleMessage(IPerson person) {
if (this.days > person.getDays()) {
this.response(person);
} else {
if (this.nextHandler != null) {
this.nextHandler.handleMessage(person);
} else {
System.out.println("員工想要請假 " + this.days + " 天,超過可以審批的最大許可權,那就不批了");
}
}
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
protected abstract void response(IPerson person);
}
這個類中最核心的部分是定義了 nextHandler 下一個責任人,如果當前的員工請假的請求不屬於自己的審批範疇,則會將這個請求轉發至下一個審批人。
接下來是三位具體的審批人:
public class Leader1 extends Handler {
// 小組長
public Leader1() {
super(Handler.MIN);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向小組長請示------------");
System.out.println(person.getResult());
System.out.println("-----------請示通過---------------");
}
}
public class Leader2 extends Handler {
// 大組長
public Leader2() {
super(Handler.MIDDLE);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向大組長請示------------");
System.out.println(person.getResult());
System.out.println("-----------請示通過---------------");
}
}
public class Leader3 extends Handler {
// 部門經理
public Leader3() {
super(Handler.MAX);
}
@Override
protected void response(IPerson person) {
System.out.println("-----------向部門經理請示--------------");
System.out.println(person.getResult());
System.out.println("-----------請示通過---------------");
}
}
然後我們來寫一個測試類:
public class Test {
public static void main(String[] args) {
Random random = new Random();
ArrayList<IPerson> personList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
personList.add(new Person(random.nextInt(30)));
}
Handler leader1 = new Leader1();
Handler leader2 = new Leader2();
Handler leader3 = new Leader3();
leader1.setNextHandler(leader2);
leader2.setNextHandler(leader3);
for (IPerson person: personList) {
leader1.handleMessage(person);
}
}
}
執行結果如下:
-----------向部門經理請示--------------
領導,我想請 17 天假!!!
-----------請示通過---------------
員工想要請假 20 天,超過可以審批的最大許可權,那就不批了
-----------向小組長請示------------
領導,我想請 0 天假!!!
-----------請示通過---------------
-----------向部門經理請示--------------
領導,我想請 11 天假!!!
-----------請示通過---------------
-----------向大組長請示------------
領導,我想請 4 天假!!!
-----------請示通過---------------
3. 責任鏈模式
責任鏈模式定義如下:
Avoid coupling the sender of a request to its receiver by giving more thanone object a chance to handle the request.Chain the receiving objects andpass the request along the chain until an object handles it.(使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。)
責任鏈模式的重點是在 「鏈」 上,由一條鏈去處理相似的請求在鏈中決定誰來處理這個請求,並返回相應的結果,這個鏈類似於一個單向連結串列的資料結構,從開始一直向後迭代,知道找不到下一個為止,它的通用類圖如下:
通用程式碼如下:
3.1 抽象 Handler
public abstract class Handler {
private Handler nextHandler;
// 每個處理者都必須對請求作出處理
public final Response handleMessage(Request request) {
Response response = null;
// 判斷當前處理級別
if (this.getHandlerLevel().equals(request.getLevel())) {
response = this.echo(request);
} else {
// 判斷是否有下一個處理者
if (this.nextHandler != null) {
response = this.nextHandler.handleMessage(request);
} else {
// 沒有匹配的業務處理者,邏輯根據具體場景實現
}
}
return response;
}
// 設定下一個處理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
protected abstract Level getHandlerLevel();
protected abstract Response echo(Request request);
}
抽象的處理者實現三個職責:
- 定義一個請求的處理方法 handleMessage ,唯一對外開放的方法。
- 定義一個鏈的編排方法 setNext ,設定下一個處理者。
- 定義了具體的請求者必須實現的兩個方法:定義自己能夠處理的級別 getHandlerLevel 和具體的處理任務 echo 。
3.2 具體處理者
public class ConcreteHandler1 extends Handler {
@Override
protected Level getHandlerLevel() {
// 設定自己的處理級別
return null;
}
@Override
protected Response echo(Request request) {
// 設定處理的業務功能
return null;
}
}
public class ConcreteHandler2 extends Handler {
@Override
protected Level getHandlerLevel() {
return null;
}
@Override
protected Response echo(Request request) {
return null;
}
}
public class ConcreteHandler3 extends Handler {
@Override
protected Level getHandlerLevel() {
return null;
}
@Override
protected Response echo(Request request) {
return null;
}
}
定義三個具體的處理者,以便組成一個鏈。
3.3 其餘相關程式碼
public class Level {
}
public class Request {
public Level getLevel() {
return null;
}
}
public class Response {
}
3.4 測試類
最後是一個測試類:
public class Test {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
Response response = handler1.handleMessage(new Request());
}
}
在實際的使用過程中,最後都會有一個封裝類對責任鏈模式進行封裝,用來取代我們現在的這個測試類,直接返回鏈中的第一個處理者,具體鏈的設定不需要高層次模組關係,這樣,更簡化了高層次模組的呼叫,減少模組間的耦合,提高系統的靈活性。
4. 優點
任鏈模式非常顯著的優點是將請求和處理分開。請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌(例如在 J2EE 專案開發中,可以剝離出無狀態 Bean 由責任鏈處理),兩者解耦,提高系統的靈活性。
5. 缺點
責任鏈有兩個非常顯著的缺點:
- 效能問題,每個請求都是從鏈頭遍歷到鏈尾,特別是在鏈比較長的時候,效能是一個非常大的問題。
- 除錯不很方便,特別是鏈條比較長,環節比較多的時候,由於採用了類似遞迴的方式,除錯的時候邏輯可能比較複雜。