责任链模式
责任链模式的解释
责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。
以上是维基百科的解释,那么通俗一点解释一下(毕竟计算机相关的解释都很计算机😄),拿的以前有人看牙的解释:
说的是一个病人看牙的时候,医生不小心把拔下的一个牙掉进了病人嗓子眼里。病人因此楼上楼下的跑了好多科室,最后无果而终(这个解释是不是印象很深刻😁)。
责任链模式就是这种“推卸”责任的模式,你的问题在我这里能解决我就解决,不行就把你推给另一个对象。至于到底谁解决了这个问题了呢?我管呢!
责任链模式的定义
由此可知——系统中将会存在多个有类似处理能力的对象。
当一个请求触发后,这个请求将在这些对象组成的链中传递,直到找到最合适的“责任”对象,并进行处理。
定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
从定义上可以看出,责任链模式的提出是为了“解耦”,以应变系统需求的变更和不明确性。
下面是适用范围:
1) 有多个的对象可以处理一个请求,哪个对象该处理该请求由runtime自动确定。
2) 在不明确指定接收者的情况下,向多个对象中的其中一个发出请求。
3) 可处理一个请求的对象集合应被动态指定。
责任链模式真的能给发送者和接收者之间解耦(这好像很神奇)吗?先来看下它的组成角色,责任链模式由两个角色组成:
1) 抽象处理者角色(Handler):它定义了一个处理请求的接口。当然对于链的不同实现,也可以在这个角色中实现后继链。
2) 具体处理者角色(Concrete Handler):实现抽象角色中定义的接口,并处理它所负责的请求。如果不能处理则访问它的后继者。
只是一个继承或者实现,这里不再展示图示。
而且,不完全符合责任链模式定义的也没关系,最终的目的是通过将多个处理者之间建立的联系,来达到请求与具体的某个处理者的解耦。
下面我们不完全匹配定义来实现一个自动生成员工工号、档案代号的功能。这些代号对于一个特定的企业或者类别,往往有一定的规则。因此可以让用户在系统参数中维护一定的规则,来给用户生成所需的代号。
首先,代号中一般存在以下几种变动元素:年、月、日、流水号。于是得到下面的大致结构(头脑风暴,不体现功能细节)。
interface CodeAutoParse {
}
class DateAutoParse implements CodeAutoParse {
private currentDate: Calendar = Calendar();
private theNextParseOfDate: CodeAutoParse;
public setTheNextParseOfDate(theNextParseOfDate: CodeAutoParse): void {
this.theNextParseOfDate = theNextParseOfDate;
}
public generateCode(moduleCode: string, number: number, rule: string, target: string[]): string[] {
//……
if (theNextParseOfDate !== null)
return this.theNextParseOfDate.generateCode(moduleCode, number, rule, target)
else
return target;
}
其它具体处理的结构也是这样,每个都设置有用来存放下一个处理者(不管你有没有下一个处理者)的引用。
责任链模式的设计
责任链模式优点主要是降低耦合、提高灵活性。但是会降低性能,因为它要从链头开始遍历。
另外,责任链模式是一种对象的行为模式:在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使系统可以在不影响客户端的情况下动态的重新组织链和分配责任。
在实现时一般会考虑:
一、结构
抽象处理者角色(Handler):定义一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回下家的引用。
抽象方法handlerRequest()规范子类处理请求的操作。
具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给后继者。由于处理者持有后继者引用,因此,如果需要,具体处理者可以访问后继者。
二、定义一致性
责任链模式定义要求一个具体的处理者对象只能在2个行为中选择一个:继承责任或者把责任推给后继者。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。一个请求必须被某一个处理者对象所接器。一般很少见到完全符合定义的实现。
但是在不完全符合定义的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。这是常见的实现方式。
以下是具体实现过程:
首先是过滤器,处理用户信息的逻辑抽象成为一个个的过滤器,进一步抽象出过滤器接口Filter:
interface IFilter {
doFilter($request: Request, $response: Response, $chain: FilterChain): void;
}
Face过滤器:
class FaceFilter implements IFilter {
public constructor(){
}
public doFilter($request: Request, $response: Response, $chain: FilterChain): void {
$request.requestStr = $request.requestStr.replace(":)", "^V^--FaceFilter");
$chain.doFilter($request, $response, $chain);
$response.responseStr += "--FaceFilter";
}
}
然后在FilterChain中继承Filter接口,实现doFilter方法:
class FilterChain implements IFilter {
private var _filters: Array = [];
private var _index: int = 0;
public constructor(){
}
public addFilter($filter: IFilter): IFilter {
_filters.push($filter);
return this;
}
public doFilter($request: Request, $response: Response, $chain: FilterChain): void {
if (_index < _filters.length) {
var f: IFilter = _filters[_index] as IFilter;
_index++;
f.doFilter($request, $response, $chain);
}
}
}
将过滤器添加到ArrayList中,再调用FilterChain的doFilter方法遍历整个责任链。
接下来是HTML过滤器:
class HTMLFilter implements IFilter{
public constructor(){
}
public doFilter($request:Request, $response:Response, $chain:FilterChain):void
{
$request.requestStr = $request.requestStr.replace("<", "[").replace(">", "] --HTMLFilter");
$chain.doFilter($request, $response, $chain);
$response.responseStr += "--HTMLFilter";
}
}
Sesitive过滤器用于过滤掉敏感词汇:
class SesitiveFilter implements IFilter
{
public constructor(){
}
public doFilter($request:Request, $response:Response, $chain:FilterChain):void
{
$request.requestStr = $request.requestStr.replace("敏感词汇", " ").replace("**", "你被娃哈哈了--SesitiveFilter");
$chain.doFilter($request, $response, $chain);
$response.responseStr += "--SesitiveFilter";
}
}
接收者:
class Response {
private _str: string;
public constructor() {
}
public get responseStr(): string {
return _str;
}
public set responseStr($str: string): void {
_str = $str;
}
}
然后是用户的请求:
class Request {
private _str: string;
public constructor() {
}
public get requestStr(): string {
return _str;
}
public set requestStr($str: string): void {
_str = $str;
}
}
最后来别忘了测试:
var request: Request = new Request();
request.requestStr = "敏感词汇,杭州,<script> 娃哈哈 :)";
var response: Response = new Response();
response.responseStr = "response";
var fc: FilterChain = new FilterChain();
fc.addFilter(new HTMLFilter());
fc.addFilter(new SesitiveFilter());
var fc2: FilterChain = new FilterChain();
fc2.addFilter(new FaceFilter());
fc.addFilter(fc2);
fc.doFilter(request, response, fc);
trace("request = " + request.requestStr);// 词汇,杭州,[script] --HTMLFilter 你被娃哈哈了--SesitiveFilter ^V^--FaceFilter
trace("response = " + response.responseStr);//response--FaceFilter--SesitiveFilter--HTMLFilter
function trace(msg: any): void {
console.log(msg);
}
code enjoy! 🧐🧐🧐
作者:indeex
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。