你的锅我不背!且看职责链模式


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 = request    return;...}

其次,我们需要再构造一个统一接口用于把这些处理对象串起来,代码非常简单,直接用一个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);       else        return NULL;    }}

中等内存处理函数和小内存处理函数也是相类似的,这里就不再一一列举了。


总结

责任链模式的核心就在"链"上,这个"链"是由多个处理对象构成的,它解耦了请求和处理,请求者不用知道是谁处理的,而处理者也可以不用知道请求是谁发过来的。请求只要将一直沿着这条"链"进行传递,直到有对象处理它就可以了。

但是责任链模式也有它的缺点,那就是当"链"比较长时,有可能会影响系统性能,因为每个请求都有可能从链头遍历到链尾嘛。大家在实际使用时需要适当注意。

end




手把手教你,拿下观察者模式|c语言!

前任写的代码,真的垃圾啊

c语言,去你的策略模式!

c语言设计模式--状态模式(状态机)



扫描二维码

获取更多精彩

just enjoy!



觉得不错,请点个在看