`
步行者
  • 浏览: 169787 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

CoR 模式(另一种)

阅读更多

CoR(Chain of Responsibility)   职责链设计模式

我在 两种 CoR(一) 中讨论了传统的CoR实现:

但我感觉 让 每个处理器都持有后继处理器的引用,会增加处理器之间的耦合度.

 

下面是我的一些想法 和 具体实现:

(1)处理器 不持有 后继处理器的引用,引入一个新的角色 处理器容器(HandlerContainer ,由容器管理每个处理器,并且这个处理器容器 也是一个处理器(实现了Handler 接口),他的处理能力是容器里所有处理器的处理能力的和。

(2)一个处理器如果不能处理传递过来的请求,则抛出一个(CanNotHandleRequestException )异常,

 如果管理这个处理器的容器接受到这个异常,则将请求传递给容器中的下一个处理器。如果容器中的所有处理器都不能处理这个请求,则由容器抛出一个(CanNotHandleRequestException )异常。

 

实现:与传统CoR相比,处理器接口(Handler )不变,请求接口(Request )和实现类不变。

1,增加CanNotHandleRequestException 异常类,当处理器不能处理传递过来的请求时就抛出这个异常。

 

public class CanNotHandleRequestException extends Exception{
	private static final long serialVersionUID = 1L;
}

 

2,增加处理器容器类(HandlerContainer ),处理器容器类也实现了处理器接口,他的处理能力是容器里所有处理器的处理能力的和。

 

public class HandlerContainer implements Handler{
	private List<Handler> handlers;
	public HandlerContainer(){
		handlers = new ArrayList<Handler>();
	} 
	public boolean add(Handler handler){
		return this.handlers.add(handler);
	}
	public boolean remove(Handler handler){
		return this.handlers.remove(handler);
	}
	public void handleRequest(Request request) throws CanNotHandleRequestException{
		int length = this.handlers.size();
		for(int i = 0 ; i < length ; i++){
			Handler handler = handlers.get(i);
			try {
				handler.handleRequest(request);
				break;
			} catch (CanNotHandleRequestException e) {
				/*
				 * 如果处理器容器里的所有处理器都不能处理该请求,
				 * 则由容器抛出 CanNotHandleRequestException 异常。
				 */
				if(i == length-1) throw e;
			}
		}
	}
}

 

3,实现处理器接口的实现类  HelpHandler   PrintHandler   SaveHandler

     HelpHandler  处理 帮助请求(HelpRequest  

 

 

public class HelpHandler implements Handler{
	public void handleRequest(Request request) throws CanNotHandleRequestException {
		if(request instanceof HelpRequest){
			System.out.println("HelpHandler  handle "+request.getClass().getSimpleName());
		}else
			throw new CanNotHandleRequestException();
	}
}

 

  PrintHandler  处理 打印请求(PrintRequest  

 

public class PrintHandler implements Handler{
	public void handleRequest(Request request) throws CanNotHandleRequestException{
		if(request instanceof PrintRequest){
			System.out.println("PrintHandler handle "+request.getClass().getSimpleName());
		}else{
			throw new CanNotHandleRequestException();
		}
	}
}
 

SaveHandler   处理 保存请求(SaveRequest  

 

public class SaveHandler implements Handler{
	public void handleRequest(Request request) throws CanNotHandleRequestException{
		if(request instanceof SaveRequest){
			System.out.println("SaveHandler handle "+request.getClass().getSimpleName());
		}else{
			throw new CanNotHandleRequestException();
		}
	}
}

 

4,客户端 Client

 

public class Client {
	public static void main(String[] args) throws CanNotHandleRequestException{
		HandlerContainer Container1 = new HandlerContainer();
		Container1.add(new HelpHandler());
		HandlerContainer Container2 = new HandlerContainer();
		Container2.add(new PrintHandler());
		Container2.add(new SaveHandler());
		Container1.add(Container2);
		
		Container1.handleRequest(new HelpRequest());
		Container1.handleRequest(new PrintRequest());
		Container1.handleRequest(new SaveRequest());
	}
}
 

运行Client 类,输出如下

 

HelpHandler handle HelpRequest
PrintHandler handle PrintRequest
SaveHandler handle SaveRequest

 

 

 

分享到:
评论
22 楼 chendw_hz 2009-12-18  
如果同时存在两个相同处理器怎么办,就是说处理器还有可能引用两个完全相同的处理器。应该set更好。
21 楼 chendw_hz 2009-12-18  
改进后的模式效率应该不高,每次发送请求都要遍历处理容器容器中所有处理器,而原来的模式只要判断是否有该处理器就可以,如果有就处理,如果没有就不处理。
而且并发的时候,有可能两个不同处理会处理同一个请求。就是说有可能其中一个处理器得不到处理。
20 楼 jenlp520 2009-11-14  
sky3380 写道
楼主为何不用返回值来判断请求是否被处理?用抛出异常的方式感觉有些不妥


跟mina的ProtocolCodecFilter一样 用抛异常来终止
19 楼 scanfprintf123 2009-11-14  
步行者 写道
hankesi2000 写道
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。


我倒不觉得这是对异常的误用
CanNotHandleRequestException 异常很明显,
代表不能处理请求而产生的异常,
能处理请求表示“正常”,

CoR模式的实现 可能有很多方法,
你可以把你的方法贴出来,
大家一起讨论一下!



Anyway,个人觉得在这里使用异常能达到这个改进的目的,但应该不是最好的方式,在楼主的第一篇COR模式中,http://www.iteye.com/topic/411182?page=1, 第一种方式是属于CLASSIC的COR模式,第二种是对于第一种的改进,为什么需要改进呢?楼主肯定也知道其弊端,但在这边,对于PrintHandler,SaveHandler的实现,怎么又退回到了开始第一种CLASSIC的COR模式中去了呢?
如:
public class PrintHandler implements Handler{   
    public void handleRequest(Request request) throws CanNotHandleRequestException{   
        if(request instanceof PrintRequest){   
            System.out.println("PrintHandler handle "+request.getClass().getSimpleName());   
        }else{   
            throw new CanNotHandleRequestException();   
        }   
    }   
}  


根据代码判断,如果request是PrintRequest的实例,则处理,否则抛出CanNotHandleRequestException异常表示我这个handler不能处理这个request,你还是找别人去吧。但是,如果哪天后来谁在实现某个Handler的时候,忘记了抛出CanNotHandleRequestException异常了呢,你又没强制我抛出CanNotHandleRequestException异常,仅仅是声明了CanNotHandleRequestException,我可以不抛出的,对吧。 那么,问题来了,按照基类的代码逻辑,不抛出CanNotHandleRequestException异常,则表示我这个handler可以处理这个request,但实际上却不是,我这个handler不能处理这个request,但也没有抛出CanNotHandleRequestException异常,基类却认为已经处理了,break了。
#HandlerContainer 中
        public void handleRequest(Request request) throws CanNotHandleRequestException{   
        int length = this.handlers.size();   
        for(int i = 0 ; i < length ; i++){   
            Handler handler = handlers.get(i);   
            try {   
                handler.handleRequest(request);   
                [color=darkred][b]break;   [/b][/color]            } catch (CanNotHandleRequestException e) {   
                /*  
                 * 如果处理器容器里的所有处理器都不能处理该请求,  
                 * 则由容器抛出 CanNotHandleRequestException 异常。  
                 */  
                if(i == length-1) throw e;   
            }   
        }   
    }   
 


所以,个人认为,这里使用异常,有点画蛇添足。 其实你这里的目的是为了解耦(handler之间),这里的基类和http://www.iteye.com/topic/411182?page=1这里实现的第二种基类合并一起即可。

如:
 public void handleRequest(Request request) throws CanNotHandleRequestException{   
        int length = this.handlers.size();   
        for(int i = 0 ; i < length ; i++){   
            Handler handler = handlers.get(i);   
                           if(canHandleRequest(request)
                           { //如果能处理这个request,则处理,并返回
                              handler.handleRequest(request);   
                              break;
                           }
                 }   
        }   
    }   


对于这种方式,即使handlerRequest方法有返回值,也可以处理,只需要在上面的代码中,改为return而不是break即可:
if(canHandleRequest(request)
                           { //如果能处理这个request,则处理,并返回
                                    return handler.handleRequest(request);   
                           }



btw:javaeye的code编辑方式真不是很好用
18 楼 scanfprintf123 2009-11-14  
步行者 写道
visitor 写道
感觉有点像Composite模式。。


有点像,但意图不同,Composite侧重于 遍历所有 一个节点的所有子节点
不过 这种职责链模式 不是遍历所有节点,当有一个子节点能够处理请求的时候,
就不会遍历余下的子节点。



这个倒不太像composite模式,在我个人看来,更像是有点退化了的监听者模式,众所周知,监听者模式主要用来处理一对多的依赖,而COR这里则是用来处理一对一的依赖,一个handler处理一个request.
17 楼 whatwhat 2009-07-03  
hankesi2000 写道
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。

这个看你对异常怎么理解,
不正常的都可以叫异常
16 楼 icewubin 2009-07-02  
支持楼主对异常的理解,自定义一个非受控异常来处理不算太复杂的业务逻辑分支,我也觉得没什么不好。
15 楼 步行者 2009-07-02  
Nightlee 写道
hankesi2000 写道
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。


支持,不能用异常来控制正常的流程,用一个Result类封装流程控制信号和业务操作返回结果是不是好一点?

用一个Result类封装流程控制信号和业务操作返回结果 当然可以。
但我不认为 利用异常控制流程是对异常的误用,
异常 即 "非正常"
流程中发生“非正常”的事情 当然也可以 “抛出”。
14 楼 Nightlee 2009-07-02  
hankesi2000 写道
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。


支持,不能用异常来控制正常的流程,用一个Result类封装流程控制信号和业务操作返回结果是不是好一点?
13 楼 步行者 2009-06-29  
hankesi2000 写道
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。


我倒不觉得这是对异常的误用
CanNotHandleRequestException 异常很明显,
代表不能处理请求而产生的异常,
能处理请求表示“正常”,

CoR模式的实现 可能有很多方法,
你可以把你的方法贴出来,
大家一起讨论一下!
12 楼 hankesi2000 2009-06-29  
使用异常的形式抛出,不进行原有的业务流程,感觉是对异常的一种误用。
楼主如果将异常改为一个状态类,然后根据状态类的具体对象而做不同的处理是否更方便一些,毕竟在链的过程中,可能有会多条路可以走。
11 楼 icewubin 2009-06-23  
whaosoft 写道
这种模式有什么好处呢?

一眼看穿,改进后的模式,调试的时候绝对方便。
10 楼 步行者 2009-06-21  
whaosoft 写道
这种模式有什么好处呢?

这算是 职责链 的另一种实现吧
相比 传统实现的方法
应该降低了 处理器之间的 耦合度
9 楼 whaosoft 2009-06-21  
这种模式有什么好处呢?
8 楼 苏飞 2009-06-21  
个人比较赞同研究一下《设计模式》。正如书中的提到的,这本书是面向对象程序设计的基础,

象楼主这样根据需要做一些改进,我觉的非常的好。



面向对象有两句话:

1.尽可能但又适当的抽象。

2.将变化的东西与不变的东西分开。

7 楼 步行者 2009-06-21  
sky3380 写道
楼主为何不用返回值来判断请求是否被处理?用抛出异常的方式感觉有些不妥


恩 ,也可以,
不过要是 处理请求本身有返回值 的时候,那就不适用了。
比如 处理一个请求,返回一个应答。
6 楼 sky3380 2009-06-21  
楼主为何不用返回值来判断请求是否被处理?用抛出异常的方式感觉有些不妥
5 楼 ninini 2009-06-19  
好像比传统的COR实现要灵活。
支持一下--
4 楼 步行者 2009-06-19  
<div class="quote_title">kjj 写道</div>
<div class="quote_div">
<div class="quote_title">引用</div>
<div class="quote_div">
<br>但我感觉 让 每个处理器都持有后继处理器的引用,会增加处理器之间的耦合度.<br>
</div>
<br>像这种关系貌似不能用耦合来定义,虽然持有后继引用,但实际上没有任何耦合关系,没有以依赖关系!!!</div>
<p><br><br>处理器之间的耦合度。<br>(1)处理器持有后继处理器的引用,处理器之间为控制耦合。<br>(2)而由容器来管理处理器,处理器之间为非直接耦合。<br><br><span style="color: #ff0000;">非直接耦合</span>:两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的 。<br><span style="color: #ff0000;">控制耦合</span>:如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合。</p>
<p> </p>
<p>控制耦合的耦合度 大于 非直接耦合</p>
<p>所以我说“让 每个处理器都持有后继处理器的引用,会增加处理器之间的耦合度.”</p>
3 楼 kjj 2009-06-19  
引用

但我感觉 让 每个处理器都持有后继处理器的引用,会增加处理器之间的耦合度.

像这种关系貌似不能用耦合来定义,虽然持有后继引用,但实际上没有任何耦合关系,没有以依赖关系!!!

相关推荐

    AGC自动增益控制电路图(AD8367、AD8361、AD820)

    当设计AGC电路时,我们可以选择两种控制模式:一种是通过外部输入实现VGA功能的模式,另一种是闭环控制,以实现AGC功能。在VGA模式下,电路可以根据外部控制电压来调节增益。而在闭环AGC模式下,反馈机制会根据信号...

    Exercise 3- 18BCE1183_r_datavis_rstudio_

    在R中,我们可以使用`cor()`函数计算变量间的皮尔逊相关系数,这是一种衡量变量线性关系强度和方向的统计量。相关系数的值介于-1和1之间,正值表示正相关,负值表示负相关,而0表示没有线性关系。 要创建相关性图,...

    lcd9648液晶原理图

    LCD9648液晶显示器是一种常见的用于嵌入式系统和单片机应用的显示设备,其原理图提供了关于如何连接和驱动该显示器的详细信息。本文将深入解析LCD9648液晶显示器的工作原理和相关知识点。 首先,LCD9648的名字表明...

    esquemargb:IGTI的Primeiro trabalhopráticodo curso de Dev Full Stack。 FO的sistema para gerar cores de acordo com opadrãorgb manipulando o DOM

    【描述】中提到的“埃斯克马尔布”可能是项目名称的另一种拼写或翻译,再次强调了项目的颜色处理主题。"Prime trabalho prático"与标题相呼应,重申这是课程的首次实践练习。描述还提到了“可以从DOM到COR或DOM的...

    大芯径光纤激光器的新进展

    光纤激光的输出功率在十余年内迅速上升,目前连续输出的光纤激光功率已达千瓦以上。...另一种方法是加大光纤的纤芯直径,并用各种方法改进它的光束质量。对以上两种方法进行介绍,并给出一部分实验结果。

    基于谐振耦合现象的三芯光子晶体光纤偏振分束器

    设计了一种三芯光子晶体光纤(PCFs)偏振分束器。利用光纤的谐振现象,实现了偏振状态的分离。当三芯光子晶体光纤中三个超模式的模式折射率满足一定条件时,将产生谐振现象。通过选择合适的光纤结构参数,可使某一偏振...

    线性回归-R:Stat 308 2020年SpringR代码

    另一个需要注意的是异方差性,即误差项的方差随解释变量的变化而变化。可以使用`plot(model)$resid`和`scale(residuals(model))`结合来看,或者使用`plot(model, which = 2)`绘制残差与 fitted 值的散点图,以检查...

    ExploratoryDataAnalysisCourseProject2

    EDA是一种通过统计图形和计算来了解数据特性和结构的方法,旨在发现模式、异常值、相关性以及可能的假设检验。它通常在数据分析流程的早期阶段进行,帮助我们形成对数据的初步认识,为后续建模或决策提供基础。 在R...

    R语言常用函数

    - **data.frame**: 创建数据框,是一种特殊的列表,每一列可以是不同类型的向量。 **2. 向量操作** - **c**: 将多个对象连接成一个向量或列表。 - **length**: 求向量或列表的长度。 - **subset**: 通过条件选择...

    2009 达内Unix学习笔记

    感觉是同一文件,删除一个,对另一个没有影响;须两个都删除才算删除。 ln -s file1 file1.sln 创建软链接。可跨系统操作,冲破操作权限;也是快捷方式。 八、时间显示 date 显示时间,精确到秒 用法 date [-u]...

Global site tag (gtag.js) - Google Analytics