1.概述
职责链模式是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止
职责链模式主要包含以下角色:
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
1.1代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| package com.zhen.studytotal.design.chain;
import lombok.AllArgsConstructor; import lombok.Data; import org.apache.commons.lang3.StringUtils;
public class ChainTest {
public static void main(String[] args) { User user = new User("zhen","123456","admin");
LoginService loginService = new LoginService(); loginService.login(user);
System.out.println("-----------------"); user.setPassword("123"); loginService.login(user); System.out.println("-----------------"); user.setPassword("123456"); user.setRole("abcd"); loginService.login(user);
} }
@Data @AllArgsConstructor class User{ private String username; private String password; private String role; }
abstract class Handle{ protected Handle next; public void next(Handle next){ this.next = next; } public abstract void doHandle(User user); }
class ValidateHandler extends Handle{ @Override public void doHandle(User user) { if (StringUtils.isBlank(user.getPassword()) || StringUtils.isBlank(user.getUsername())){ System.out.println("用户名或密码为空!"); } System.out.println("用户名密码校验通过"); next.doHandle(user); } }
class LoginHandler extends Handle { @Override public void doHandle(User user) { if (!"zhen".equals(user.getUsername()) || !"123456".equals(user.getPassword())) { System.out.println("用户名或者密码不正确!请检查!"); return; } System.out.println("登陆成功!角色为管理员!"); next.doHandle(user); } }
class AuthHandler extends Handle { @Override public void doHandle(User user) { if (!"admin".equals(user.getRole())) { System.out.println("无权限操作!"); return; } System.out.println("角色为管理员,可以进行下一步操作!"); } }
class LoginService{ public void login(User user){ Handle validateHandler = new ValidateHandler(); Handle loginHandler = new LoginHandler(); Handle authHandler = new AuthHandler();
validateHandler.next(loginHandler); loginHandler.next(authHandler);
validateHandler.doHandle(user); } }
|
1.2 结合建造者模式实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public abstract class Handler<T> { protected Handler next; public Handler next(Handler next) { this.next = next; return next; } public abstract void doHandler(User user); static class Builder<T> { private Handler<T> head; private Handler<T> tail; public Builder<T> addHandler(Handler<T> handler) { if (this.head == null) { this.head = this.tail = handler; return this; } this.tail.next(handler); this.tail = handler; return this; } public Handler<T> build() { return this.head; } } } public class LoginService { public void login(User user) { Handler.Builder builder = new Handler.Builder(); builder.addHandler(new ValidateHandler()) .addHandler(new LoginHandler()) .addHandler(new AuthHandler()); builder.build().doHandler(user); } }
|
1.3 总结
适用场景:
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
优点:
- 将请求与处理解耦。
- 请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象。
- 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果。
- 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
- 易于扩展新的请求处理类(节点),符合开闭原则。
缺点:
- 责任链太长或者处理时间过长,会影响整体性能。
- 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。