博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
责任链模式
阅读量:7130 次
发布时间:2019-06-28

本文共 9864 字,大约阅读时间需要 32 分钟。

hot3.png

       责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

一.介绍

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

何时使用:在处理消息的时候以过滤很多道。

如何解决:拦截的类都实现统一接口。

应用实例: 1、红楼梦中的"击鼓传花" 2JS 中的事件冒泡。 3JAVA 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版本研发中。。)

未完,持续更新!

转载于:https://my.oschina.net/liyixiangBlog/blog/359313

你可能感兴趣的文章
私有网盘nextcloud 12的问题处理及优化
查看>>
安装VMWare Tools
查看>>
XenDesktop7-基于SCVMM2012SP1的部署
查看>>
超融合、低成本、高可用私有云解决方案
查看>>
Android应用程序键盘(Keyboard)消息处理机制分析(4)
查看>>
从第三方企业邮箱迁移至Office 365(21V) Exchange Online
查看>>
【中级】华为路由器OSPF手把手配置举例(ENSP实现)
查看>>
乔布斯逝世一周年,库克做得很棒!
查看>>
企业云桌面-10-准备虚拟机-111-CTXdb01-121-CTXLic01-131-CTXSF01-141-CTXDDC01
查看>>
Docker容器固定IP分配
查看>>
Exchange Server 2016管理系列课件54.DAG管理之执行服务器级别的切换
查看>>
SFB 项目经验-20-Skype for Business for Android-下载到电脑
查看>>
SQL Server 2012笔记分享-57:数据文件和日志文件放置最佳实践
查看>>
CentOS 6.5 LVM磁盘管理学习笔记
查看>>
友链SEO工具:换链神器测试体验
查看>>
Xcode 4.5运行时出现iOS 模拟器找不到SDK
查看>>
第三章 Python丰富的数据类型
查看>>
VMM2012应用指南之9-向VMM中添加VMware ESX Server主机
查看>>
运维监控利器Nagios之:Nagios的日常维护和管理
查看>>
ERP-SAP Business One 食品行业方案
查看>>