责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
一.介绍
意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:在处理消息的时候以过滤很多道。
如何解决:拦截的类都实现统一接口。
应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。
使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。
以上是对责任链模式的大致介绍,网上都有,本文不再重复啰嗦。
二.实战篇(方便今后快速理解并二次使用模式)
背景:
Proxy类
if (mqMessage.getMessageActionCode() == MMSMessageActionCode.ALBUM_INSERT.getDbValue()) {// 专辑添加 getBean("albumAddListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.ALBUM_UPDATE.getDbValue()) {// 专辑修改 getBean("albumUpdateListener").handleMessage(mqMessage);}else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.ALBUM_DELETE.getDbValue()) {// 专辑删除 getBean("albumDeleteListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.VIDEO_INSERT.getDbValue()) {// 视频添加 getBean("videoAddListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.VIDEO_UPDATE.getDbValue()) {// 视频修改 getBean("videoUpdateListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.VIDEO_DELETE.getDbValue()) {// 视频删除 getBean("videoDeleteListener").handleMessage(mqMessage);}else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.DICTIONARY_DELETE.getDbValue()) {// 字典删除 getBean("dictionaryDeleteListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.DICTIONARY_INSERT.getDbValue()) {// 字典添加 getBean("dictionaryInsertListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.DICTIONARY_UPDATE.getDbValue()) {// 字典修改 getBean("dictionaryUpdateListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.STAR_INSERT.getDbValue()) {// 明星添加 getBean("starInsertListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.STAR_UPDATE.getDbValue()) {// 明星修改 getBean("starUpdateListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.TV_INSERT.getDbValue()) {// 电视台添加 getBean("tvInsertListener").handleMessage(mqMessage);} else if (mqMessage.getMessageActionCode() == MMSMessageActionCode.TV_UPDATE.getDbValue()) {// 电视台修改 getBean("tvUpdateListener").handleMessage(mqMessage);}
流程:
MQ发送消息,根据actionCode使用分支if-else判断具体操作类型。
缺点:
(1)扩展性不好
(2)判断分支过于庞大
(3)且请求者与处理者紧耦合。
责任链1.0版
AbstractListenerChain责任链抽象类
public abstract class AbstractListenerChain implements IMQHandler{ protected AbstractListenerChain nextListenerChain; //下一个责任链节点的引用 protected byte actionCode; //请求判断规则 public void setActionCode(byte actionCode) { this.actionCode = actionCode; } public byte getActionCode() { return actionCode; } public void setNextListenerChain(AbstractListenerChain nextListenerChain) { this.nextListenerChain = nextListenerChain; } /** * * @throws Exception * @liyixiang * @TODO: * 接收MQ中的消息,根据ActionCode来判断 * 是何种操作类型。 */ public void receiveMessageRequest(byte actionCode,IMessage mqMessage) throws Exception{ //判断actionCode是否符合 if(getActionCode() == actionCode){ handleMessage(mqMessage); } //如果不符合,继续向下传递请求 if(nextListenerChain !=null){ nextListenerChain.receiveMessageRequest(actionCode, mqMessage); } } //具体处理消息的业务方法 public abstract void handleMessage(IMessage mqMessage) throws Exception;
改进后的Proxy类
AbstractListenerChain abstractListenerChain = getFirstListenerNode();//返回当前链节点abstractListenerChain.receiveMessageRequest(mqMessage.getMessageActionCode(), mqMessage);
构建责任链的方法private AbstractListenerChain getFirstListenerNode(){ //初始化所有链节点 AbstractListenerChain albumAddListener = (AbstractListenerChain) getBean("albumAddListener"); AbstractListenerChain albumUpdateListener = (AbstractListenerChain)getBean("albumUpdateListener"); AbstractListenerChain albumDeleteListener = (AbstractListenerChain)getBean("albumDeleteListener"); AbstractListenerChain videoAddListener = (AbstractListenerChain)getBean("videoAddListener"); AbstractListenerChain videoUpdateListener =(AbstractListenerChain)getBean("videoUpdateListener"); AbstractListenerChain videoDeleteListener =(AbstractListenerChain)getBean("videoDeleteListener"); AbstractListenerChain dictionaryInsertListener = (AbstractListenerChain)getBean("dictionaryInsertListener"); AbstractListenerChain dictionaryUpdateListener = (AbstractListenerChain)getBean("dictionaryUpdateListener"); AbstractListenerChain dictionaryDeleteListener = (AbstractListenerChain)getBean("dictionaryDeleteListener"); AbstractListenerChain starInsertListener = (AbstractListenerChain)getBean("starInsertListener"); AbstractListenerChain starUpdateListener = (AbstractListenerChain)getBean("starUpdateListener"); AbstractListenerChain tvInsertListener = (AbstractListenerChain)getBean("tvInsertListener"); AbstractListenerChain tvUpdateListener = (AbstractListenerChain)getBean("tvUpdateListener"); //设置每个节点ActionCode albumAddListener.setActionCode(MMSMessageActionCode.ALBUM_INSERT.getDbValue()); albumUpdateListener.setActionCode(MMSMessageActionCode.ALBUM_UPDATE.getDbValue()); albumDeleteListener.setActionCode(MMSMessageActionCode.ALBUM_DELETE.getDbValue()); videoAddListener.setActionCode(MMSMessageActionCode.VIDEO_INSERT.getDbValue()); videoUpdateListener.setActionCode(MMSMessageActionCode.VIDEO_UPDATE.getDbValue()); videoDeleteListener.setActionCode(MMSMessageActionCode.VIDEO_DELETE.getDbValue()); dictionaryInsertListener.setActionCode(MMSMessageActionCode.DICTIONARY_INSERT.getDbValue()); dictionaryUpdateListener.setActionCode(MMSMessageActionCode.DICTIONARY_UPDATE.getDbValue()); dictionaryDeleteListener.setActionCode(MMSMessageActionCode.DICTIONARY_DELETE.getDbValue()); starInsertListener.setActionCode(MMSMessageActionCode.STAR_INSERT.getDbValue()); starUpdateListener.setActionCode(MMSMessageActionCode.STAR_UPDATE.getDbValue()); tvInsertListener.setActionCode(MMSMessageActionCode.TV_INSERT.getDbValue()); tvUpdateListener.setActionCode(MMSMessageActionCode.TV_UPDATE.getDbValue()); //形成责任链 albumAddListener.setNextListenerChain(albumUpdateListener); albumUpdateListener.setNextListenerChain(albumDeleteListener); albumDeleteListener.setNextListenerChain(videoAddListener); videoAddListener.setNextListenerChain(videoUpdateListener); videoUpdateListener.setNextListenerChain(dictionaryInsertListener); dictionaryInsertListener.setNextListenerChain(dictionaryUpdateListener); dictionaryUpdateListener.setNextListenerChain(dictionaryDeleteListener); dictionaryDeleteListener.setNextListenerChain(starInsertListener); starInsertListener.setNextListenerChain(starUpdateListener); starUpdateListener.setNextListenerChain(tvInsertListener); tvInsertListener.setNextListenerChain(tvUpdateListener); //返回首节点 return albumAddListener; }
改进后:
(1)请求者与处理者解耦,请求者不再关心最终是谁处理了它发送过去的消息
(2)今后扩展,只需继承责任链抽象类,无需多重判断
缺点:
(1)初始化责任链代码过大,且处理者之间耦合。
责任链2.0版
AbstractListenerChain
public abstract class AbstractListenerChain implements IMQHandler{ protected AbstractListenerChain nextListenerChain; //下一个责任链节点的引用 public void setNextListenerChain(AbstractListenerChain nextListenerChain) { this.nextListenerChain = nextListenerChain; } /** * * @throws Exception * @liyixiang * @TODO: * 接收MQ中的消息,根据ActionCode来判断 * 是何种操作类型。 */ public void receiveMessageRequest(IMessage mqMessage) throws Exception{ //判断actionCode是否符合 if(compareActionCode(mqMessage)){ handleMessage(mqMessage); } //如果不符合,继续向下传递请求 if(nextListenerChain !=null){ nextListenerChain.receiveMessageRequest(mqMessage); } } //具体处理消息的业务方法 public abstract void handleMessage(IMessage mqMessage) throws Exception; //请求比较判断方法 protected abstract boolean compareActionCode(IMessage mqMessage); //actionCode比较规则 protected boolean compareRules(byte actionCode,IMessage mqMessage){ return actionCode == mqMessage.getMessageActionCode(); }}
具体XX处理者子类
@Override protected boolean compareActionCode(IMessage mqMessage) { // TODO Auto-generated method stub return compareRules(MMSMessageActionCode.ALBUM_INSERT.getDbValue(),mqMessage); }
注:
对于actionCode的初始化放在了各个处理者类中,责任链类只需调用compareActionCode方法,即判断决定是否处理消息。具体的compareRules比较规则相同,就可以抽象在抽象类中统一实现,各个处理者只需调用即可完成判断
改进后:
(1)各个处理者解耦,各自处理各自请求,互不相干。
(2)今后增加责任链节点也无需再修改proxy类的代码
缺点:
(1)
//形成责任链 albumAddListener.setNextListenerChain(albumUpdateListener); albumUpdateListener.setNextListenerChain(albumDeleteListener); albumDeleteListener.setNextListenerChain(videoAddListener); videoAddListener.setNextListenerChain(videoUpdateListener); videoUpdateListener.setNextListenerChain(videoDeleteListener); videoDeleteListener.setNextListenerChain(dictionaryInsertListener); dictionaryInsertListener.setNextListenerChain(dictionaryUpdateListener); dictionaryUpdateListener.setNextListenerChain(dictionaryDeleteListener); dictionaryDeleteListener.setNextListenerChain(starInsertListener); starInsertListener.setNextListenerChain(starUpdateListener); starUpdateListener.setNextListenerChain(tvInsertListener); tvInsertListener.setNextListenerChain(tvUpdateListener);
串联责任链依然存在于proxy消息发送类中,应当将请求者与处理者完全解耦,使用工厂模式来创建出链节点对象。(3.0版本研发中。。)
未完,持续更新!