今天与大家谈一谈责任链模式 (Chain of Responsibility Pattern)。
**目的**
在发送请求的类和最终处理的类之间进行解耦。
**例子代码**
小伙伴们都看过 大头儿子小头爸爸 么(大手牵小手, 走路不怕滑~)当初纯洁的我怎么也没想到小头爸爸的绿帽子这么鲜艳...
话说大家都这么说, 大头妈妈天天在家里生气, 小头爸爸内心也忍不住了, 于是要证明自己的清(bei)白(lv)😳
除了王叔叔, 还有二个他很怀疑的对象:尖鼻子厨师和粗眉毛保安大哥。
他现在就想看看这到底是谁的责任,这个时候他采取了如下的代码。
定义一个大头儿子类:
@Getterpublic class BigHeadSon { //是否尖鼻子 private final boolean pointedNose = false; //是否粗眉毛 private final boolean coarseEyebrows = false; //是否大头 private final boolean bigHead = true;}
定义一个决定儿子爸爸的类:
public class DecideFather { public static String findFatherName (BigHeadSon son) { if (son.isPointedNose()) { return "尖鼻子厨师"; } if (son.isCoarseEyebrows()) { return "粗眉毛保安"; } if (son.isBigHead()) { return "隔壁老王"; } return "小头爸爸"; }}
然后小头爸爸试了试:
public class App { public static void main(String[] args) { System.out.println(DecideFather. findFatherName(new BigHeadSon())); }}
**问题分析**
很明显, if-else 可能无限的地方就是设计模式可以使用的地方。
这时候比如他又怀疑了卖狗狗的大胡子叔叔, 那他又要加个 if-else 了, 这个函数最终可能上百行, 变量可能共享, 那他就很难受了😫
**责任链模式**
先定义一套责任链的共有类:
public interface ChainNode <T extends AbstractChainNodeResponse> { <C extends AbstractChainNodeContext, R extends AbstractChainNodeRequest> ChainResult<T> execute(C context, R request);}
其中的类都是空实现, chainResult 如下:
@Datapublic class ChainResult <T extends AbstractChainNodeResponse> <T extends AbstractChainNodeResponse> { private boolean processingCompleted; private T response;}
定义一个责任链处理器:
public class ChainProcessor { public static <T extends AbstractChainNodeResponse> T handleChainNodes(List<ChainNode<T>> chainNodes, AbstractChainNodeContext context, AbstractChainNodeRequest request, T defaultValue) AbstractChainNodeContext context, AbstractChainNodeRequest request, T defaultValue){ for (ChainNode<T> chainNode : chainNodes) { ChainResult<T> execute = chainNode.execute(context, request); if (execute.isProcessingCompleted()) { return execute.getResponse(); } } return defaultValue; }}
然后我们结合例子代码进行使用:
自定义返回值:
@Data@NoArgsConstructor@AllArgsConstructorpublic class FatherNameChainNodeResponse extends AbstractChainNodeResponse extends AbstractChainNodeResponse { //父亲姓名 private String fatherName;}
使得大头儿子继承入参类:
@Getterpublic class BigHeadSon extends AbstractChainNodeRequest extends AbstractChainNodeRequest { //是否尖鼻子 private final boolean pointedNose = false; //是否粗眉毛 private final boolean coarseEyebrows = false; //是否大头 private final boolean bigHead = true;}
实现一个抽象的找爸爸类:
public abstract class CheckFatherChainNode implements ChainNode<FatherNameChainNodeResponse> { @Override public ChainResult<FatherNameChainNodeResponse> execute(AbstractChainNodeContext context, AbstractChainNodeRequest request){ return null; }}
尖鼻子检查:
public class NoseCheckFatherChainNode extends CheckFatherChainNode { @Override public ChainResult<FatherNameChainNodeResponse> execute(AbstractChainNodeContext context, AbstractChainNodeRequest request) { BigHeadSon bigHeadSon = (BigHeadSon) request; ChainResult<FatherNameChainNodeResponse> chainResult = new ChainResult<>(); if (bigHeadSon.isPointedNose()) { chainResult.setProcessingCompleted(true); chainResult.setResponse( new FatherNameChainNodeResponse("尖鼻子厨师")); } return chainResult; }}
粗眉毛检查:
public class EyeBrowCheckFatherChainNode extends CheckFatherChainNode { @Override public ChainResult<FatherNameChainNodeResponse> execute(AbstractChainNodeContext context, AbstractChainNodeRequest request) { BigHeadSon bigHeadSon = (BigHeadSon) request; ChainResult<FatherNameChainNodeResponse> chainResult = new ChainResult<>(); if (bigHeadSon.isCoarseEyebrows()) { chainResult.setProcessingCompleted(true); chainResult.setResponse( new FatherNameChainNodeResponse("粗眉毛保安")); } return chainResult; }}
大头检查:
public class HeadCheckFatherChainNode extends CheckFatherChainNode { @Override public ChainResult<FatherNameChainNodeResponse> execute(AbstractChainNodeContext context, AbstractChainNodeRequest request) { BigHeadSon bigHeadSon = (BigHeadSon) request; ChainResult<FatherNameChainNodeResponse> chainResult = new ChainResult<>(); if (bigHeadSon.isBigHead()) { chainResult.setProcessingCompleted(true); chainResult.setResponse( new FatherNameChainNodeResponse("隔壁老王")); } return chainResult; }}
最终使用:
public class App { public static void main(String[] args) { System.out.println(ChainProcessor .handleChainNodes( Arrays.asList( new NoseCheckFatherChainNode(), new EyeBrowCheckFatherChainNode(), new HeadCheckFatherChainNode()), null, new BigHeadSon(), new FatherNameChainNodeResponse("小头爸爸"))); }}
一顿操作猛如虎, 一看还是带绿帽......
**责任链课后作业**
1. 结合 bean 声明学习在 Spring boot 中优雅使用责任链模式
2. 学习使用 Apache Commons Chain 包
3. 作为一个银行开发人员, 我们有个支用请求, 需要验证支用币种是否是CNY(人民币),用户是否在黑名单,是否是实名认证的用户,支用的产品是否可用,支用金额是否充足等, 请使用责任链模式完成
提供了如下入参:
@Datapublic class LendRequest { //支用金额 private String loanAmt; //支用币种 private String currency; //支用产品 private String pdCode; //用户唯一标识 private String userId;}
提供的接口如下:
public class Client { //是否不在黑名单 public static boolean isNotInBlack(String userId) { return true; } //是否是实名认证用户 public static boolean isRealUser(String userId) { return true; } //是否产品可用 public static boolean isPdUsable(String pdCode) { return true; } //是否用户额度充足 public static boolean isHasSoMuchMoney(String userId, String loanAmt) { return false; }}
codog代码狗 wx: