come on
伸出中指戳戳上方关注我……

模式动机
责任链模式在日常生活里面非常普遍,比如说小时候上学的时候,老师每次让我们缴一些书本费用,作为小朋友自己肯定是没钱,只好回家把缴费信息告诉爸妈,爸妈身上可能也没钱,于是只好去亲戚家借钱。最后由亲戚家出这个钱。这就是责任链模式,在整个问题的解决过程,节节相扣,看起来就像是构成了一条"链"。
在程序开发过程中,我们经常会遇到很多类似的场景。比如在一个物流配送系统中,一般会根据货物重量大小来安排不同的运输车辆,小快递派三轮车送,大一点的快递就要安排面包车、甚至小货车等。
场景案例
在大部分操作系统中,针对不同的内存申请大小,设置了不同的内存分配算法,比如在Linux系统里面就针对大内存和小内存分配,分别使用了Buddy和Slab分配算法。在某些系统里面甚至还有超大内存分配算法。
在这里,我们假定:大于4KB内存申请,使用大内存分配算法;小于4KB但大于1KB内存申请,使用中等内存分配算法;小于1KB,则使用小内存分配算法。
伪代码实现如下:
void main(){char *p1,*p2,*p3;...//申请大内存p1 = malloc(10KB);//申请中等内存p2 = malloc(2KB);//申请小内存p2 = malloc(100);...}void* malloc(int size){...if(size > 4KB)//调用大内存分配函数return big_malloc(int size);else if( size >= 1KB && size <= 4KB )//调用中等内存分配函数return middle_malloc(int size);else//调用小内存分配函数return small_malloc(int size);...}
事实上,很多开发者都是习惯使用类似上面的if...else..或者是switch...case...语句来处理复杂情况,这样一来就会造成程序有大量的分支判断,造成难维护、灵活性差。

改进方案
首先,要把处理的函数分离出来,具体的做法是把条件和相应的处理函数,抽象到同一个处理对象中,然后通过指针把这些不同的处理对象串起来。如下图:
//定义处理函数类型typedef void* (*func)(strcut assign* pAssign,int value);//处理对象typedef struct assign{//链表指针struct assign* next;//条件范围int max;int min;//处理函数func request;};
接下来,我们要有一个统一的对象初始化接口,去初始化这个对象的max值、min值和处理函数。如下所示:
void set_value(struct assign* pAssign, int max, int min,func request;){...pAssign->max = max;pAssign->min = min;pAssign->request = requestreturn;...}
其次,我们需要再构造一个统一接口用于把这些处理对象串起来,代码非常简单,直接用一个next指针保存下一个对象的起始地址就可以了(其实就是一个单向链表)
void set_next_assign(struct assign* pAssign, struct assign* next){pAssig->next = next;return;}
有了前面的两个接口,我们已经可以初始化并串起来这些处理对象了,在我们这个例子里面的话,总共是有三个处理对象, 我们在程序中把它们串起来就可以了。如下图:

光把各个处理对象串联还不行,最后,我们还要再为各个对象的构造处理函数。构造的时候注意以下两点就可以了:
如果当前条件符合自己的处理范围,则直接处理
如果当前条件不符合自己的处理范围,则传递给下一个对象处理
比如大内存处理对象的处理函数,我们可以这样构造:
//大内存处理算法void* big_request(strcut assign* pAssign,int value);{//判断当前条件是否符合处理要求,如果符合要求直接处理if(value > pAssign->min && value =< pAssign->max )return big_malloc(int size);//如果不符合要求,传递给下一个函数处理else{//判断下一个对象是否存在if(pAssign->next)return pAssign->next->request(pLeader->next, value);elsereturn NULL;}}
中等内存处理函数和小内存处理函数也是相类似的,这里就不再一一列举了。
总结
责任链模式的核心就在"链"上,这个"链"是由多个处理对象构成的,它解耦了请求和处理,请求者不用知道是谁处理的,而处理者也可以不用知道请求是谁发过来的。请求只要将一直沿着这条"链"进行传递,直到有对象处理它就可以了。
但是责任链模式也有它的缺点,那就是当"链"比较长时,有可能会影响系统性能,因为每个请求都有可能从链头遍历到链尾嘛。大家在实际使用时需要适当注意。
end


扫描二维码
获取更多精彩
just enjoy!



觉得不错,请点个在看
