前言
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
使用责任链模式是避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
实际使用
一个事件需要经过多个对象处理是一个挺常见的场景,譬如检验系统的检验流程。
电梯的检验流程
起重机检验流程
代码
github地址:https://github.com/shaweiwei/mall-tiny-docker-file
整体图
抽象流程处理类AbstractProcessHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
/** * @author shamo */ @Data public abstract class AbstractProcessHandler { protected ProcessStep processStep; protected AbstractProcessHandler nextProcessHandler; public void dealWithRequest(ProcessRequestDTO processRequestDTO){ handle(processRequestDTO); if (nextProcessHandler != null){ nextProcessHandler.dealWithRequest(processRequestDTO); } } abstract void handle(ProcessRequestDTO processRequestDTO); } |
每个流程步骤对应的处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * @author shamo */ @Slf4j @Component public class InspectionApplyHandler extends AbstractProcessHandler { public InspectionApplyHandler() { this.processStep = ProcessStep.INSPECTION_APPLY; } @Override void handle(ProcessRequestDTO processRequestDTO) { log.info("current step {}, content {}", processStep.getName(), processRequestDTO.toString()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
import com.macro.mall.tiny.config.ProcessStep; import com.macro.mall.tiny.dto.ProcessRequestDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * @author shamo */ @Slf4j @Component public class InstructionIssueHandler extends AbstractProcessHandler { public InstructionIssueHandler() { this.processStep = ProcessStep.INSTRUCTION_ISSUE; } @Override void handle(ProcessRequestDTO processRequestDTO) { log.info("current step {}, content {}", processStep.getName(), processRequestDTO.toString()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
import com.macro.mall.tiny.config.ProcessStep; import com.macro.mall.tiny.dto.ProcessRequestDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * @author shamo */ @Slf4j @Component public class InspectHandler extends AbstractProcessHandler { public InspectHandler() { this.processStep = ProcessStep.INSPECT; } @Override void handle(ProcessRequestDTO processRequestDTO) { log.info("current step {}, content {}", processStep.getName(), processRequestDTO.toString()); } } |
|
/** * @author shamo */ @Slf4j @Component public class CheckHandler extends AbstractProcessHandler { public CheckHandler() { this.processStep = ProcessStep.CHECK; } @Override void handle(ProcessRequestDTO processRequestDTO) { log.info("current step {}, content {}", processStep.getName(), processRequestDTO.toString()); } } |
两个枚举类
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
|
/** * 流程步骤 * @author shamo */ public enum ProcessStep { /** * 检测申请 */ INSPECTION_APPLY("0", "inspectionApply"), /** * 检测指令下发 */ INSTRUCTION_ISSUE("1", "instructionIssue"), /** * 检验员检验 */ INSPECT("2", "inspect"), /** * 审核人审核 */ CHECK("3", "check"); private String code; private String name; ProcessStep(String code, String name) { this.code = code; this.name = name; } public String getName() { return name; } public String getCode() { return code; } @Override public String toString() { return getName(); } } |
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
|
/** * @author shamo */ public enum EquipmentType { /** * 检测申请 */ LIFT("0", "lift"), /** * end */ CRANE("1", "crane"); private String code; private String name; EquipmentType(String code, String name) { this.code = code; this.name = name; } public String getName() { return name; } public String getCode() { return code; } @Override public String toString() { return getName(); } public static EquipmentType getByCode(String code){ for(EquipmentType processStep : EquipmentType.values()){ if(code.equals(processStep.getCode())){ return processStep; } } return null; } } |
service类和实现类
|
import com.macro.mall.tiny.config.EquipmentType; import com.macro.mall.tiny.dto.ProcessRequestDTO; public interface ProcessService { void dispose(EquipmentType equipmentType, ProcessRequestDTO processRequestDTO); } |
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
|
import com.macro.mall.tiny.config.EquipmentType; import com.macro.mall.tiny.dto.ProcessRequestDTO; import com.macro.mall.tiny.handler.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; /** * @author shamo */ @Service public class ProcessServiceImpl implements ProcessService { @Autowired private InspectionApplyHandler inspectionApplyHandler; @Autowired private InstructionIssueHandler instructionIssueHandler; @Autowired private InspectHandler inspectHandler; @Autowired private CheckHandler checkHandler; @Override public void dispose(EquipmentType equipmentType, ProcessRequestDTO processRequestDTO) { if (equipmentType == EquipmentType.LIFT){ inspectionApplyHandler.setNextProcessHandler(instructionIssueHandler); }else{ inspectionApplyHandler.setNextProcessHandler(inspectHandler); } instructionIssueHandler.setNextProcessHandler(inspectHandler); inspectHandler.setNextProcessHandler(checkHandler); inspectionApplyHandler.dealWithRequest(processRequestDTO); } } |
DTO类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
import lombok.Data; import java.io.Serializable; /** * @author shamo */ @Data public class ProcessRequestDTO implements Serializable { private static final long serialVersionUID = 4498181465722961122L; private String taskId; // ... } |
Controller类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
import com.macro.mall.tiny.config.EquipmentType; import com.macro.mall.tiny.dto.ProcessRequestDTO; import com.macro.mall.tiny.service.ProcessService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * @author shamo */ @RequestMapping("process") @RestController public class ProcessController { @Autowired private ProcessService processService; @PostMapping(value = "/dispose/{equipmentCode}") public void dispose(@RequestBody ProcessRequestDTO processRequestDTO, @PathVariable String equipmentCode) { processService.dispose(EquipmentType.getByCode(equipmentCode), processRequestDTO); } } |
启动类
|
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MallTinyApplication { public static void main(String[] args) { SpringApplication.run(MallTinyApplication.class, args); } } |
application.yml
启动后用postman测试
先测试电梯检验流程
|
2020-07-05 17:58:35.665 INFO 16156 --- [nio-8047-exec-7] c.m.m.t.handler.InspectionApplyHandler : current step inspectionApply, content ProcessRequestDTO(taskId=1111) 2020-07-05 17:58:35.666 INFO 16156 --- [nio-8047-exec-7] c.m.m.t.handler.InstructionIssueHandler : current step instructionIssue, content ProcessRequestDTO(taskId=1111) 2020-07-05 17:58:35.666 INFO 16156 --- [nio-8047-exec-7] c.m.mall.tiny.handler.InspectHandler : current step inspect, content ProcessRequestDTO(taskId=1111) 2020-07-05 17:58:35.666 INFO 16156 --- [nio-8047-exec-7] c.macro.mall.tiny.handler.CheckHandler : current step check, content ProcessRequestDTO(taskId=1111) |
再测试起重机检验流程
|
2020-07-05 17:58:51.338 INFO 16156 --- [nio-8047-exec-8] c.m.m.t.handler.InspectionApplyHandler : current step inspectionApply, content ProcessRequestDTO(taskId=1111) 2020-07-05 17:58:51.338 INFO 16156 --- [nio-8047-exec-8] c.m.mall.tiny.handler.InspectHandler : current step inspect, content ProcessRequestDTO(taskId=1111) 2020-07-05 17:58:51.339 INFO 16156 --- [nio-8047-exec-8] c.macro.mall.tiny.handler.CheckHandler : current step check, content ProcessRequestDTO(taskId=1111) |
总结
责任链的代码核心是nextHandler,这边因为我的两个链(电梯检验流程和起重机检验流程)是事先知道的,所以直接预先把每个handler的nexthandler设置好了。有的时候我们可能需要根据请求的具体参数(ProcessRequestDTO)里的不同属性值动态判断某个handler的nextHandler,那就可以在具体的Handler的重写的handle方法里根据参数决定set哪个handler为nextHandler。