什么是責任鏈?
責任鏈模式是行為模式的一種,它將需要觸發的Handler組成一條鏈,發送者將請求發給鏈的第一個接收者,并且沿著這條鏈傳遞,直到有一個Handler來處理它或者直到最后也沒有對象處理而留在鏈末尾端;責任連模式的重點是在鏈上,由一條鏈去處理相似的請求,在鏈中決定誰來處理這個請求
責任鏈分為純責任鏈與不純責任鏈(一般實戰應用較多)
**純職責鏈 **
1.每個處理者接收到請求后,要么單純轉發請求,要么單純處理請求。不允許既處理請求,又轉發請求的情況。
2.請求必須被責任鏈上的某個處理者處理。不允許出現請求未被處理的情況。
**不純職責鏈 **
1.每個處理者接收到請求后,除了單純轉發請求,或者單純處理請求,還可以部分處理請求后,轉發。
2.請求可以不被責任鏈上的任何處理者處理。
責任鏈優點
1.解耦請求者和處理者。
2.非常靈活,可以任意組裝
3.各個節點的責任明確
缺點
1.每次都是從鏈頭開始。
2. 可能造成死循環。責任鏈如果是環狀的,可能會導致循環調用,造成死循環。
純責任鏈的代碼Demo:
/**
* 在公司OA系統請假審批流程
如果請假小于3天只需要項目經理批復就行;
如果請假大于等于3天,小于7天需要人事經理批復了;
如果請假大于等于7天,小于15天需要總經理批復了;
如果申請請假大于等于15天,決絕批復......
* @param args
*/
public static void main(String[] args) {
Leader manager = new Manager("張三");
Leader hrManager = new HrManager("李四");
Leader generalManager = new GeneralManager("王麻子");
//組織責任鏈對象的關系
manager.setNextLeader(hrManager);
hrManager.setNextLeader(generalManager);
//請假
LeaveRequest request = new LeaveRequest("parry", 10, "回家相親!");
manager.dealLeaveRequest(request);
}
public abstract class Leader {
// 領導姓名
protected String name;
// 責任鏈上的后繼對象
protected Leader nextLeader;
public Leader(String name) {
super();
this.name = name;
}
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
public abstract void dealLeaveRequest(LeaveRequest request);
}
public class HrManager extends Leader{
public HrManager(String name) {
super(name);
}
@Override
public void dealLeaveRequest(LeaveRequest request) {
if (3 <= request.getLeaveDay() && request.getLeaveDay() < 7) {
System.out.println("人事經理:" + name + " 審批了 " + request.getEmployee() + "請假" + request.getLeaveDay()
+ "天的請求,請假原因:" + request.getReason());
} else {
if (this.nextLeader != null) {
this.nextLeader.dealLeaveRequest(request);
}
}
}
}
public class GeneralManager extends Leader {
public GeneralManager(String name) {
super(name);
}
@Override
public void dealLeaveRequest(LeaveRequest request) {
if (7 <= request.getLeaveDay() && request.getLeaveDay() <= 15) {
System.out.println("總經理:" + name + " 審批了 " + request.getEmployee() + "請假" + request.getLeaveDay()
+ "天的請求,請假原因:" + request.getReason());
} else {
System.out.println(
"總經理:" + name + " 拒絕了 " + request.getEmployee() + "請假" + request.getLeaveDay() + "天的請求,請假不能超過15天");
}
}
}
public class Manager extends Leader{
public Manager(String name) {
super(name);
}
@Override
public void dealLeaveRequest(LeaveRequest request) {
if (request.getLeaveDay() < 3) {
System.out.println("經理:" + name + " 審批了 " + request.getEmployee() + "請假" + request.getLeaveDay()
+ "天的請求,請假原因:" + request.getReason());
} else {
if (this.nextLeader != null) {
this.nextLeader.dealLeaveRequest(request);
}
}
}
}
@Data
public class LeaveRequest {
//姓名
private String name;
//請假天數
private int leaveDay;
//請假原因
private String reason;
public LeaveRequest(String name, int leaveDay, String reason) {
this.name=name;
this.leaveDay=leaveDay;
this.reason=reason;
}
}
電商售后使用責任鏈(不純責任鏈)
售后業務梳理
電商售后常見三種模式:
僅退款、退款退貨、退款換貨
售后業務可分為
僅退款: 采購商申請——>商家審核——>完成
退款退貨:采購商申請——>商家審核——>采購商發貨——>商家確認收貨——>完成
退款換貨:采購商申請——>商家審核——>采購商發貨——>商家確認收貨——>商家發出新品——>采購商確認收貨——>完成
僅退款的實際退款等操作在商家審核時,而退款退貨和退款換貨則在確認收貨時。
以下為售后責任鏈流程:
售后->校驗退款單狀態->原路退款(以下單支付方式為準)->退積分或其它優惠->更新訂單及對應商品退款信息->保存結算->保存財務流水->保存/更新退款日志->發送退款成功異步消息
三種售后的核心退款業務流程基本是一致的,少個別節點業務邏輯有所區別,將核心業務抽成責任鏈的各個節點,這對售后來說,代碼的復用性提高了很多,同時業務處理更加清晰,犯錯率大大降低。
以下為售后中代碼使用Demo
定義一個節點的基類接口
public interface BaseRefundHandler {
void handle(PipelineContext context) ;
}
售后責任鏈組裝,以下以僅退款為例
public class RefundPipeBean {
/**
* 僅退款,責任鏈初始化節點
*/
public List<String> refundPipe = new ArrayList<>();
public List<String> getRefundPipe() {
refundPipe.add("checkRefundStatus"); //校驗退款單狀態
refundPipe.add("refundMoney"); //原路退款(獲取訂單支付方式)
refundPipe.add("returnScore"); //退積分或其它優惠券類
......
return refundPipe;
}
@Bean
@Scope("prototype")
public CheckRefundStatus checkRefundStatus() {return new CheckRefundStatus();}
@Bean
@Scope("prototype")
public RefundMoney refundMoney() {return new RefundMoney();}
......
}
** 注: 這個配置就等同于之前在xml里的配置**
"checkRefundStatus" class="com.xx.CheckRefundStatus"/>
創建一個啟動監聽器
@Component
public class RefundPipeListener extends ApplicationObjectSupport implements InitializingBean {
private static Map<String, List > handlersMap = new HashMap<>();
public static Map<String, List> getHandlersMap() {
return handlersMap;
}
//最好定義成全局的,此處因演示 才在類中寫 。 責任鏈的名稱
public static String ONLY_REFUND="ONLY_REFUND";
@Override
public void afterPropertiesSet() throws Exception {
RefundPipeBean refundPipeBean=new RefundPipeBean();
//裝載退款業務鏈.....
List normalHandlers=new ArrayList<>();
for (String s : refundPipeBean.getRefundPipe()) {
BaseRefundHandler normalHandler = (BaseRefundHandler) getApplicationContext().getBean(s);
normalHandlers.add(normalHandler);
handlersMap.put(ONLY_REFUND, normalHandlers);
}
}
}
創建節點傳遞對象所用POJO類
@Data
public class PipelineContext<K, V> extends ConcurrentHashMap<K, V> {
protected boolean success = false;
//責任鏈結束標識
protected boolean isEnd = false;
protected String resultCode;
private Object data;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean isEnd() {
return isEnd;
}
public void setEnd(boolean end) {
isEnd = end;
}
}
public class RefundPipelineContext<K, V> extends PipelineContext<K, V> {
/**
* 封裝退款單信息
*/
private RefundInfoPipeVo refundInfoPipeVo;
public RefundInfoPipeVo getRefundInfoPipeVo() {
return refundInfoPipeVo;
}
public void setRefundInfoPipeVo(RefundInfoPipeVo refundInfoPipeVo) {
this.refundInfoPipeVo = refundInfoPipeVo;
}
}
創建節點
public class CheckRefundStatus implements BaseRefundHandler {
@Override
public void handle(PipelineContext<String, RefundInfoPipeVo> context) {
//業務邏輯 todo
......
//表示該節點運行正常,可以繼續向下走
context.setSuccess(true);
}
}
業務調用層
@RestController
public class RefundInfoController {
@Autowired
RefundInfoService refundInfoService;
@ApiOperation("僅退款")
@RequestMapping(value = "/auditRefund", method = {RequestMethod.GET, RequestMethod.POST}, produces = "application/json;charset=UTF-8")
public RespData<Boolean> auditRefund(xxx) {
refundInfoService.auditRefund(xxx);
return RespData.success("審核成功",true);
}
}
public interface RefundInfoService {
void auditRefund(xxx);
}
@Service("refundInfoService")
public class RefundInfoServiceImpl implements RefundInfoService {
@Override
public void auditRefund(xxx) {
//業務邏輯 todo
RefundInfoResultVo refundInfoResultVo = refundInfoMapper.queryById(platformId, refundId);
......
PipelineContext<String, RefundInfoPipeVo> refund = new RefundPipelineContext<>();
//在責任鏈中傳遞參數對象
refund.put("refund", refundInfoResultVo);
Map<String, List> map = RefundPipelineChangeListener.getHandlersMap();
//通過責任鏈的名稱獲取對應鏈 。 此處key值應為一個全局的常量,與上面監聽器中的鏈條名一致
List baseRefundHandlers = map .get(ONLY_REFUND);
for (BaseRefundHandler handler : baseRefundHandlers) {
handler.handle(refund);
if (refund.isEnd()) {
System.out.println("責任鏈執行結束...");
break;
}
if (!refund.isSuccess()) {
System.out.println("責任鏈執行失敗...");
break;
}
}
}
}
整體總結
以上是責任鏈在業務中創建及使用的流程。
同時以上流程也還存在一些可優化點:
- 責任鏈節點硬編碼問題
- 添加同步事務控制
-
模式
+關注
關注
0文章
65瀏覽量
13383 -
handler
+關注
關注
0文章
7瀏覽量
3033
發布評論請先 登錄
相關推薦
評論