Java设计模式-责任链模式
责任链模式: 将能够处理某一类请求的对象串成一条链, 请求沿链传递, 链上的对象逐个判断是否有能力处理该请求. 使多个对象都有机会处理请求, 从而避免请求发送者和接收者之间的耦合关系.
(图片来源: 设计模式: 可复用面向对象软件的基础)
优势: 发出请求的客户端并不知道链上的哪个对象最终处理该请求, 这使得系统可以在不影响客户端的前提下动态地重新组织和分配责任.
模式实现
案例: 雇员要求 (请假 & 涨薪), 要经过总监Director -> 经理Manager -> 总经理GeneralManager的层层审批.
Handler:
定义一个处理请求的接口, 内持继任者(可选):
public abstract class Leader {
protected Leader superior;
protected String name;
protected Leader(Leader superior, String name) {
this.superior = superior;
this.name = name;
}
public abstract void handle(Request request);
}
ConcreteHandler
处理它所负责的请求, 可访问它的后继者;
如果可处理该请求, 处理之, 否则将请求转发:
// 总监
class Director extends Leader {
public Director(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 10) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总监 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 经理
class Manager extends Leader {
public Manager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 20) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 经理 [" + name + "] 审批通过");
} else if (request.getType().equals("涨薪") && request.getCount() <= 1000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 经理 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 总经理
class GeneralManager extends Leader {
public GeneralManager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假")) {
if (request.getCount() <= 30) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("[ " + request.getContent() + "] 你干脆辞职算了");
}
} else if (request.getType().equals("涨薪")) {
if (request.getCount() <= 10_000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("你咋不上天呢");
}
}
}
}
Client
向链上的具体处理者对象提交请求:
public class Client {
@Test
public void client() {
Leader generalManger = new GeneralManager(null, "刘备");
Leader manager = new Manager(generalManger, "诸葛亮");
Leader director = new Director(manager, "赵云");
director.handle(new Request("请假", "翡青", 32));
director.handle(new Request("涨薪", "zjf", 1500));
}
}
public class Request {
private String type;
private String content;
private int count;
public Request() {
}
public Request(String type, String content, int count) {
this.type = type;
this.content = content;
this.count = count;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
注: 非链表实现责任链 - 还可通过集合、数组等形式存储责任链, 很多项目中, 每个具体的Handler并不是开发团队定义的, 而是项目上线后又外部单位追加的, 此时使用链表方式定义chain of responsibility就很困难, 此时可选择使用集合存储.
小结
优缺点
降低耦合度: 客户提交一个请求, 请求沿链传递直至一个ConcreteHandler最终处理, 接收者和发送者都没有对方的明确信息, 便于接受者与发送者的解耦.
增强给对象指派职责的灵活性: 链中对象自己并不清楚链结构,他们仅保持一个后继者指针, 因此责任链可简化对象的相互连接, 且可以随时增加或修改处理请求的对象, 增强了给对象指派职责的灵活性.
缺陷: 不保证被接受: 既然一个请求没有明确的接收者, 那么就不能保证它能一定被正确处理, 即一个请求有可能到了链的末端也得不到处理, 或因为没有正确配置链顺序而得不到“正确”处理.
场景
有多个对象可以处理一类请求, 且哪个对象处理由运行时刻自动确定;
在不明确指定接收者的情况下, 向多个对象中提交同一个请求;
处理一个请求的对象集合被动态指定;
Java异常机制: 一个try对应多个catch;
Servlet: Filter链式处理;
Spring MVC : 拦截器链(详见: Spring MVC 实践);
相关模式
Composite(组合)模式: 这种情况下, 一个构件的父构件可作为它的后继者.
- sed+awk模拟简单sql查询(26天)
- 海量数据迁移之冲突数据筛查(r2 第1天)
- sqlldr加载性能问题的排查 (r2第2天)
- sqlplus无法启动的问题及解决(3) (25天)
- sqlplus无法启动的问题及解决(2) (25天)
- 10g升级至11g exp的问题解决(23天)
- redo日志文件学习(22天)
- 数据库文件的迁移
- excel文件内容导入数据库的问题及解决(20天)
- 10g,11g数据泵的导入问题及解决(19天)
- ORACLE 11g导入9i dump的问题及解决
- 服务器增加内存后无法重启数据库的问题及解决 (36天)
- 分区表放入keep pool,recycle pool的问题及解析(34天)
- 临时表空间故障处理 (33天)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Windows下安装及使用NVM
- U盘上安装多个Linux发行版和PE
- ubuntu18.04部署python3、nginx项目
- CentOS8.x系统配置记录
- js根据经纬度换算行驶里程
- ubuntu18.04 安装docker
- COBBLER无人值守批量安装系统.md
- 使用VSCode 打包你的第一个flutter应用(安卓篇)
- KICKSTART无人值守批量安装系统.md
- Centos7-Firewall防火墙基础讲解
- 优酷iOS插件化页面架构方法
- 处理一次k8s、calico无法分配podIP的心路历程
- 小视频源码,按返回键两次退出
- iOS音视频接入 - TRTC多人音视频通话
- Android平台RTMP推流或轻量级RTSP服务(同屏或摄像头)编码前数据接入类型总结