从击鼓传花说起:
击鼓传花是一种热闹而又紧张的饮酒游戏。在酒宴上宾客依次坐定位置,由一人击鼓,击鼓的地方与传花的地方是分开的,以示公正。开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在某人手中,则该人就得饮酒。
击鼓传花便是责任链模式的应用。责任链可能是一条直线、一个环链或者一个树结构的一部分。
责任链模式涉及到的角色如下所示:
-
抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
-
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
责任链模式1:
事件经过责任链的每一个环节,各个环节只处理"属于"自己的那一部分。
(举例:去医院看病, 挂号–> 医生开检查单 --> 做检查 -->医生看病 -->病房抓药)
代码实现:
参数:
public class MyDto {
private String type;
private String name;
public MyDto(String type, String name) {
this.type = type;
this.name = name;
}
//toString
//get...
//set...
}
抽象处理者角色:
public interface MyHandle {
Object handMethod(MyDto dto);
}
具体处理者1:
public class OneMyHandle implements MyHandle {
@Override
public Object handMethod(MyDto dto) {
if ("111".equals(dto.getType())) {
//业务逻辑处理...
}
return null;
}
}
具体处理者2:
public class TwoMyHandle implements MyHandle {
@Override
public Object handMethod(MyDto dto) {
if ("222".equals(dto.getType())) {
//业务逻辑处理...
}
return null;
}
}
客户端:
public class TestForMyHandle {
public static void main(String[] args) {
MyHandle h1 = new OneMyHandle();
MyHandle h2 = new TwoMyHandle();
MyDto myDto = new MyDto("type", "name");
List<MyHandle> list = new ArrayList<>(2);
list.add(h1);
list.add(h2);
//遍历执行每一个"环节"
for (MyHandle handle : list) {
handle.handMethod(myDto);
}
}
}
责任链模式2:
在责任链模式1中,事件会经过链上的每一环节,有些情况是没必要经过全部环节的,可以在链上的任意一个环节进行中断返回。
比如下面这个场景: 在公司请假,请半天或1天假需要组长审批即可,请2-3天假,需要直系经理进行审批,请4-5天假需要部门经理审批,请超过5天假期需要公司高层审批。
入参:
public class HDto {
//请假天数
private Integer days;
//请假原因
private String reason;
//请假人
private String name;
public HDto(Integer days, String reason, String name) {
this.days = days;
this.reason = reason;
this.name = name;
}
//get set toString...
}
出参:
public class HVo {
//t: 同意请假 f: 拒绝请假
private Boolean result;
//审批原因
private String msg;
public HVo(Boolean result, String msg) {
this.result = result;
this.msg = msg;
}
//get set toString
}
抽象处理者角色:
public abstract class Handle {
//下一个处理者
Handle handle;
//处理事件
public HVo dealAbsence(HDto dto) {
return null;
}
//设置下一个处理者
public void setNextHandle(Handle handle) {
this.handle = handle;
}
//获取下一个处理者
public Handle getNextHandle() {
return handle;
}
}
具体处理者(组长):
public class TeamLeaderHandle extends Handle {
@Override
public HVo dealAbsence(HDto dto) {
if (dto.getDays() < 2) {
//其他逻辑判断
// ...
System.out.println(String.format("组长批准,%s: 请假%d天成功",dto.getName(),dto.getDays()));
return new HVo(true, "组长批准, 请假成功");
}
//交给下一个处理
return getNextHandle().dealAbsence(dto);
}
}
具体处理者(直系经理):
public class DirectManagerHandle extends Handle {
@Override
public HVo dealAbsence(HDto dto) {
if (1 < dto.getDays() && dto.getDays() < 4) {
//其他逻辑判断
System.out.println(String.format("直系经理批准,%s: 请假%d 天成功",dto.getName(),dto.getDays()));
return new HVo(true, "直系经理批准, 请假成功");
}
//交给下一个处理
return getNextHandle().dealAbsence(dto);
}
}
具体处理者(部门经理):
public class DeptManagerHandle extends Handle {
@Override
public HVo dealAbsence(HDto dto) {
if (3 < dto.getDays() && dto.getDays() < 6) {
//其他逻辑判断
System.out.println(String.format("部门经理批准,%s: 请假%d 天成功",dto.getName(),dto.getDays()));
return new HVo(true, "部门经理批准, 请假成功");
}
//交给下一个处理
return getNextHandle().dealAbsence(dto);
}
}
具体处理者(公司高管):
public class TopHandle extends Handle {
@Override
public HVo dealAbsence(HDto dto) {
if (dto.getDays() > 5) {
//业务逻辑判断
//....
System.out.println(String.format("公司高管批准,%s: 请假%d 天成功", dto.getName(), dto.getDays()));
return new HVo(true, "公司高管批准, 请假成功");
}
return null;
}
}
测试:
public class TestForHandle {
public static void main(String[] args) {
Handle handle1 = new TeamLeaderHandle();
Handle handle2 = new DirectManagerHandle();
Handle handle3 = new DeptManagerHandle();
Handle handle4 = new TopHandle();
//上一个处理者持有下一个处理者
handle1.setNextHandle(handle2);
handle2.setNextHandle(handle3);
handle3.setNextHandle(handle4);
handle1.dealAbsence(new HDto(1, "肚子疼", "张三"));
System.out.println("----------------------------------------------");
handle1.dealAbsence(new HDto(3, "肚子疼", "张三"));
System.out.println("----------------------------------------------");
handle1.dealAbsence(new HDto(5, "肚子疼", "张三"));
System.out.println("----------------------------------------------");
handle1.dealAbsence(new HDto(7, "肚子疼", "张三"));
}
}
其他
Tomcat的filter属于第二种模式的应用。