使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止java
假設如今開發一個在線訂購系統。但願對系統訪問進行限制,只容許認證用戶建立訂單。但是,在接下來的幾個月裏,不斷有新的需求提了出來....緩存
檢查代碼原本就已經混亂不堪,而每次新增功能都會使其更加臃腫。修改某個檢查步驟有時會影響其餘的檢查步驟。系統會變得讓人很是費解,並且其維護成本也會激增安全
責任鏈會將特定行爲轉換爲被稱做處理者的獨立對象。每一個檢查步驟均可被抽取爲僅有單個方法的類,並執行檢查操做。請求及其數據則會被做爲參數傳遞給該方法。而且,鏈上的每一個處理者都有一個成員變量來保存對於下一處理者的引用。處理者接收到請求後自行決定是否可以對其進行處理。若是本身可以處理,處理者就再也不繼續傳遞請求。不然,請求會在鏈上移動, 直至全部處理者都有機會對其進行處理。所以在這種狀況下,每一個請求要麼最多有一個處理者對其進行處理,要麼沒有任何處理者對其進行處理 oop
1)單一職責原則。 可對發起操做和執行操做的類進行解耦flex
2)開閉原則。 能夠在不更改現有代碼的狀況下在程序中新增處理者ui
3)加強了給對象指派職責的靈活性this
4)請求可能一直到鏈的末端都得不處處理spa
middleware/Middleware.java: 基礎驗證接口code
package chain_of_responsibility.middleware; /** * @author GaoMing * @date 2021/7/21 - 21:16 */ public abstract class Middleware { private Middleware next; /** * Builds chains of middleware objects. */ public Middleware linkWith(Middleware next) { this.next = next; return next; } /** * Subclasses will implement this method with concrete checks. */ public abstract boolean check(String email, String password); /** * Runs check on the next object in chain or ends traversing if we're in * last object in chain. */ protected boolean checkNext(String email, String password) { if (next == null) { return true; } return next.check(email, password); } }
middleware/ThrottlingMiddleware.java: 檢查請求數量限制component
package chain_of_responsibility.middleware; /** * @author GaoMing * @date 2021/7/21 - 21:16 */ public class ThrottlingMiddleware extends Middleware{ private int requestPerMinute; private int request; private long currentTime; public ThrottlingMiddleware(int requestPerMinute) { this.requestPerMinute = requestPerMinute; this.currentTime = System.currentTimeMillis(); } /** * Please, not that checkNext() call can be inserted both in the beginning * of this method and in the end. * * This gives much more flexibility than a simple loop over all middleware * objects. For instance, an element of a chain can change the order of * checks by running its check after all other checks. */ public boolean check(String email, String password) { if (System.currentTimeMillis() > currentTime + 60_000) { request = 0; currentTime = System.currentTimeMillis(); } request++; if (request > requestPerMinute) { System.out.println("Request limit exceeded!"); Thread.currentThread().stop(); } return checkNext(email, password); } }
middleware/UserExistsMiddleware.java: 檢查用戶登陸信息
package chain_of_responsibility.middleware; import chain_of_responsibility.server.Server; /** * @author GaoMing * @date 2021/7/21 - 21:16 */ public class UserExistsMiddleware extends Middleware{ private Server server; public UserExistsMiddleware(Server server) { this.server = server; } public boolean check(String email, String password) { if (!server.hasEmail(email)) { System.out.println("This email is not registered!"); return false; } if (!server.isValidPassword(email, password)) { System.out.println("Wrong password!"); return false; } return checkNext(email, password); } }
middleware/RoleCheckMiddleware.java: 檢查用戶角色
package chain_of_responsibility.middleware; /** * @author GaoMing * @date 2021/7/21 - 21:17 */ public class RockCheckMiddleware extends Middleware{ public boolean check(String email, String password) { if (email.equals("admin@example.com")) { System.out.println("Hello, admin!"); return true; } System.out.println("Hello, user!"); return checkNext(email, password); } }
server/Server.java: 受權目標
package chain_of_responsibility.server; import chain_of_responsibility.middleware.Middleware; import java.util.HashMap; import java.util.Map; /** * @author GaoMing * @date 2021/7/21 - 21:22 */ public class Server { private Map<String, String> users = new HashMap<>(); private Middleware middleware; /** * Client passes a chain of object to server. This improves flexibility and * makes testing the server class easier. */ public void setMiddleware(Middleware middleware) { this.middleware = middleware; } /** * Server gets email and password from client and sends the authorization * request to the chain. */ public boolean logIn(String email, String password) { if (middleware.check(email, password)) { System.out.println("Authorization have been successful!"); // Do something useful here for authorized users. return true; } return false; } public void register(String email, String password) { users.put(email, password); } public boolean hasEmail(String email) { return users.containsKey(email); } public boolean isValidPassword(String email, String password) { return users.get(email).equals(password); } }
Demo.java: 客戶端代碼
package chain_of_responsibility; import chain_of_responsibility.middleware.Middleware; import chain_of_responsibility.middleware.RockCheckMiddleware; import chain_of_responsibility.middleware.ThrottlingMiddleware; import chain_of_responsibility.middleware.UserExistsMiddleware; import chain_of_responsibility.server.Server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @author GaoMing * @date 2021/7/21 - 21:15 */ public class Demo { private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); private static Server server; private static void init() { server = new Server(); server.register("admin@example.com", "admin_pass"); server.register("user@example.com", "user_pass"); // All checks are linked. Client can build various chains using the same // components. Middleware middleware = new ThrottlingMiddleware(2); middleware.linkWith(new UserExistsMiddleware(server)) .linkWith(new RockCheckMiddleware()); // Server gets a chain from client code. server.setMiddleware(middleware); } public static void main(String[] args) throws IOException { init(); boolean success; do { System.out.print("Enter email: "); String email = reader.readLine(); System.out.print("Input password: "); String password = reader.readLine(); success = server.logIn(email, password); } while (!success); } }
執行結果
Enter email: admin@example.com Input password: admin_pass Hello, admin! Authorization have been successful! Enter email: user@example.com Input password: user_pass Hello, user! Authorization have been successful!
責任鏈模式、命令模式、中介者模式和觀察者模式用於處理請求發送者和接收者之間的不一樣鏈接方式:
1. 責任鏈按照順序將請求動態傳遞給一系列的潛在接收者,直至其中一名接收者對請求進行處理
2. 命令在發送者和請求者之間創建單向鏈接
3. 中介者清除了發送者和請求者之間的直接鏈接, 強制它們經過一箇中介對象進行間接溝通
4. 觀察者容許接收者動態地訂閱或取消接收請求
例如,當用戶點擊按鈕時,按鈕產生的事件將沿着GUI元素鏈進行傳遞,最開始是按鈕的容器(如窗體或面板),直至應用程序主窗口。鏈上第一個能處理該事件的元素會對其進行處理
使用示例:責任鏈模式在Java程序中並不常見,由於它僅在代碼與對象鏈打交道時才能發揮做用。該模式最流行的使用案例之一是在GUI類中將事件向上傳遞給父組件。另外一個值得注意的使用案例是依次訪問過濾器
下面是該模式在覈心 Java 程序庫中的一些示例:
識別方法:該模式可經過一組對象的行爲方法間接調用其餘對象的相同方法來識別,並且全部對象都會遵循相同的接口