后台开发学习笔记(十二、责任链模式)

不知不觉中来到了设计模式这部分,设计模式之前一直想学的,那时候都没什么驱动力,现在有了,一边学习一边写笔记,这种学习方法也是比较好的,毕竟有输出,写的过程中考虑都了好些东西,要不然写不清楚,不说了,进入主题,这次用的语言是C++。

12.1 引入

我看着别人说设计模式的时候,都会有引入的,不过也确实是,直接上来就说责任链模式,感觉有点奇怪,还是要先引入,通过生活的例子,再到抽象,然后到代码的实现,也才是我们程序员的必修课。

12.1.1 生活中的例子

我们要去银行贷款,小于1万的银行职员都可以审批,大于1万的银行职员就批不了了,需要上报经理,经理收到这个请求就来办理,但是经理的权限也是有限的,只能批到十万,再往上的批不了,需要向更高级的领导请示
在这里插入图片描述
像这种方式的,就是比较符合责任链模式,总要找到一个有权限的人来处理我这件事情。

12.1.2 原来的实现

如果按照我们以前惯有的思想,就是会在类的方法中,搞很多个if else if来判断哪一个人是有权限处理的。这样导致写的处理这个方法中,写了很多死代码,以后要添加其他的领导的话,就要直接修改这个方法的代码,确实不理想。所有需要抽象一种设计模式来解决这个问题。这个过渡的地方可以参考《大话设计模式》。

12.2 责任链模式

不知道引入写的怎么样,我感觉还是不好,不是专业的,并且也懒的写那种没有设计模式的代码,如果要好好看这种铺垫可以去看看《大话设计模式》,引入写的就比较好,看了会有种谎言大悟的感觉。

12.2.1 概念

责任链模式:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

翻译一下:就是说需要把发送者的请求,发送出去,这个请求是在一条链上传输的,这个链上分别有不同的对象去接收,对象接收之后会判断自己的权限,如果不够,就继续在链上传输给下一个对象,直到有对象处理这个请求。

12.2.2 结构图

刚学了uml图的结构,现在可以小示一波
在这里插入图片描述
第一次画,不过感觉画uml图确实结构比较明确,Request类是消息类,负责发送消息,Handler类是处理消息的父类,其他的职员,经理行长都继承了这个handler类,类中的handle方法就是处理消息的。setNext这个方法是设置链条的。

12.3 代码实现

第一次写c++,一边百度一遍写,写的不好,如果有什么问题,可以私信找我。不过通过这次写c++,感觉对c++的类的语法有点认识了。

12.3.1 Request类

Request是发送消息的类,就是这个消息在链条上传递,这个类只要有贷款的金额loan,其他的个人的信息,比如名字,年龄等,不过我们关注的还是loan。

class Resqest
{
    public:
        Resqest(const std::string& name, int age, int loan) : _age(age), _name(name), _loan(loan){   //冒号是赋值

        }

        int get_loan() {
            return _loan;
        }

        int get_type_loan() {
            return type_loan;
        }

    private:
        unsigned int type_loan = 10000;     //单位为1万
        unsigned int _loan; 
        unsigned short _age;
        std::string _name;
};

这里添加一个c++的语法:Resqest(const std::string& name, int age, int loan) : _age(age), _name(name), _loan(loan) 构造函数函数后面的冒号第一种用法:
_age(age) _age是类中的变量,age是外部传进来的。

12.3.2 Handler类

Handler是第一个处理的类,这个类的内容多了一点,只要是这个类作为基类,其他的总监,市行长都是继承这个类。

class Handler
{
public:
    Handler(Handler *handler) {
        printf("handler 构造函数\n");
        set_next(handler);
    }

    void handle(Resqest* resq) {
        printf("gjgj %d %d %d %d\n", resq->get_loan(), resq->get_type_loan(), max_loan, type_loan);
        if(resq->get_loan() * resq->get_type_loan() < max_loan * type_loan) {
            printf("找到了 max_loan=%d\n", max_loan * type_loan);
        }else if(next_handler != nullptr){
            printf("找下一个 %p\n", next_handler);
            next_handler->handle(resq);
        }else {
            printf("结束了\n");
        }
    }

    void show() {
        printf("Handler %p %d\n", next_handler, max_loan);
    }

    int set_max_loan(unsigned int max_loan) {
        this->max_loan = max_loan;
    }
protected:
    Handler *next_handler;

private:
    unsigned int max_loan = 1;
    unsigned int type_loan = 10000;   //单位是1万
    void set_next(Handler *handler) {
        next_handler = handler;
    }
};

set_next():这个函数就是设置链条的函数,传入的参数下一个handler的指针,每一个类都有Handler *next_handler;这个指针,这个指针就负责指向下一个handler的。

set_max_loan():这个函数是设置每一个类中的最大贷款值,在判断的时候是用的到的。

handle():这个函数就是真正处理的函数,判断Request类传递过来的消息中的贷款金额是否符合当前类的权限,如果不满足并且下一个handler不为空,就执行next_handler->handle(resq);下一个handler的handle函数,直到handler为空的时候,说明链条已经结束,这时候都不满足,退出。

12.3.3 Employee类

这个是职员的类,是比handler权限高一级的类,要继承handler类,因为handler类好多方法都已经实现了,继承过来直接使用即可。跟handler类不同的地方,就是设置贷款金额。这里用了一个设置金额的函数设置了不同权限的金额。

class Employee : public Handler
{
public:
    Employee(Handler *next) : Handler(next) {
        printf("employee\n");
        set_max_loan(max_loan);
    }

protected:
    unsigned int max_loan = 10;
};

其他行长、市行长、省行长的类,都按照这种方式实现,这里就不写出来了。

12.3.4 main函数

重点是我们的main函数,怎么把链条构建出来的,main函数就可以直接体现出来了,就是上面说的用set_next(),的方法。

/**
    * @brief  main函数
    * @param  
    * @retval 
    */ 
    int main(void)
    {
        printf("hello c++\n");
        
        //先申请个消息的类,利用构造函数,填写各个变量的值
        Resqest *resq = new Resqest("Tibin", 22, 10);

        //市行长,创建一个对象,参数nullptr,市行长我目前实现的是最后一个,没有后继
        CityBankManager *cManager = new CityBankManager(nullptr);
        //行长,行长的后继就是市行长,这是直接调用构造函数的方法,设置后继指针的
        BankManager *bManager = new BankManager(cManager);
        Employee *employ = new Employee(bManager);
        Handler *handler = new Handler(employ);
        
        //从最低级的开始调用handle处理函数,handle函数内部有判断是不是找后继的情况
        handler->handle(resq);

        return 0;
    }

这个代码应该不难,理解一下就懂了。

12.4 总结

责任链的特点:

  1. 责任链可简化对象的相互连接,它们仅需要保存一个指向后继的引用,而不需要保存所有的候选这的引用。这样大大的降低了耦合度。
  2. 随时地增加或修改处理一个请求的结构。增加了给对象指派职责的灵活性。
  3. 一个请求极有可能到了末端都得不到处理,或者因为配置不当而得不到处理,这就需要考虑全面。
    参考《大话设计模式》

这一篇内容比较少,也不难,所以写的有点少。

发布了32 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/C1033177205/article/details/104058305