设计模式 c++版(11)——责任链模式

定义:

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


示例一:责任链模式(通用版)


1. 类图16-4

2. 代码清单

//////////////////    **********  3. 责任链模式(通用版),代码清单16-3:***************//


enum EType
{
    EType1  = 1,
    EType2     ,
    EType3
};

class IRequest
{
public:
    virtual EType       getType()       = 0;      
    virtual QString     getRequest()    = 0;      
};

class Request:public IRequest
{
public:
    Request(EType type, QString request)
    {
        this->m_type    = type;
        this->m_request = request;
    }
    virtual EType  getType()
    {
        return this->m_type;
    }
    virtual QString getRequest()
    {
        return this->m_request;
    }
    
private:
    EType     m_type;
    QString   m_request;   
};

class Handler
{
public:
    Handler(){}
    Handler(EType type)
    {
        this->m_type = type;
    }
    
    void    handleMessage(IRequest *request)
    {
        if (request->getType() == this->m_type)
        {
            this->response(request);
        }
        else
        {
            if (this->m_nextHandler != nullptr)
            {
                this->m_nextHandler->handleMessage(request);
            }
            else
            {
                qDebug() << "NO!";
            }   
        }
    }
    void    setNext(Handler *handler)
    {
        this->m_nextHandler = handler;
    }
protected:
    virtual void    response(IRequest *request) = 0;

protected:
    Handler     *m_nextHandler;
    EType        m_type;
};

class ConcreteHandler1:public Handler
{
public:
    ConcreteHandler1()
    {
        this->m_type = EType1;
    }

protected:
    virtual void    response(IRequest *request)
    {
        qDebug() << "request:" << request->getRequest();
    }
};

class ConcreteHandler2:public Handler
{
public:
    ConcreteHandler2()
    {
        this->m_type = EType1;
    }

protected:
    virtual void    response(IRequest *request)
    {
        qDebug() << "request:" << request->getRequest();
    }
};

class ConcreteHandler3:public Handler
{
public:
    ConcreteHandler3()
    {
        this->m_type = EType1;
    }

protected:
    virtual void    response(IRequest *request)
    {
        qDebug() << "request:" << request->getRequest();
    }
};

class Client
{
public:
    Client()
    {
        QString strRequest = "***";
        for (int i = 0; i < 5; ++i)
        {
            srand((unsigned)time(NULL)); 
            int num = rand() % (4 - 1) + 1;
            EType type = EType(num);
            IRequest* request = new Request(type, strRequest);
            m_requests.push_back(request);
        }
    }
    void    request()
    {
        Handler *handler1   = new ConcreteHandler1();
        Handler *handler2   = new ConcreteHandler2();
        Handler *handler3   = new ConcreteHandler3();
        handler1->setNext(handler2);
        handler2->setNext(handler3);
        
        QList<IRequest*>::ConstIterator iter = m_requests.begin();
        while(iter != m_requests.end())
        {
            IRequest* request = *iter;
            if (request->getType() == EType1)
            {
                handler1->handleMessage(request);
            }
            else if (request->getType() == EType2)
            {
                handler2->handleMessage(request);    
            }
            else if (request->getType() == EType3)
            {
                handler3->handleMessage(request);
            }
            else{}
            
            ++iter;
        }
    } 
    
private:
    QList<IRequest*> m_requests;
};

int main()
{
    Client client;
    client.request();
    
    return 0;
}


示例二:妇女“三从”(初始设计)

1.需求分析:

妇女出门,出嫁前请示父亲,出嫁后请示丈夫,丈夫不在请示儿子

2. 类图16-1


3. 类图说明

IHandler 是三个有决策权对象的接口, IWomen 是女性的代码


4.代码清单16-1

////////////////    **********  1. 妇女“三从”初始设计,代码清单16-1:***************//

enum EType
{
    ENotMarry    = 1,
    EMarry          ,
    ENothusband
};

class IWomen
{
public:
    virtual int     getType()       = 0;      //获得个人状况
    virtual QString getRequest()    = 0;      //获得个人请示
};

class Women:public IWomen
{
public:
    Women(EType type, QString request)
    {
        this->m_type    = type;
        this->m_request = request;
    }
    virtual int getType()
    {
        return this->m_type;
    }
    virtual QString getRequest()
    {
        return this->m_request;
    }
    
private:
    int     m_type;
    QString m_request;
};

class IHandler
{
public:
    virtual void    HandleMessage(IWomen *women) = 0;
};

class Father:public IHandler
{
public:
    virtual void    HandleMessage(IWomen *women)
    {
        qDebug() << "request:" << women->getRequest();
        qDebug() << "Father restore: ...";
    }
};

class Husband:public IHandler
{
public:
    virtual void    HandleMessage(IWomen *women)
    {
        qDebug() << "request: "<< women->getRequest();
        qDebug() << "Husband restore: ...";
    }
};

class Son:public IHandler
{
public:
    virtual void    HandleMessage(IWomen *women)
    {
        qDebug() << "request: "<< women->getRequest();
        qDebug() << "Son restore: ...";
    }
};

class Client
{
public:
    Client()
    {
        QString request = "***";
        for (int i = 0; i < 5; ++i)
        {
            srand((unsigned)time(NULL)); 
            int num = rand() % (4 - 1) + 1;
            EType type = EType(num);
            IWomen* women = new Women(type, request);
            m_womens.push_back(women);
        }
    }
    void    request()
    {
        IHandler *father    = new Father();
        IHandler *husband   = new Husband();
        IHandler *son       = new Son();
        QList<IWomen*>::ConstIterator iter = m_womens.begin();
        while(iter != m_womens.end())
        {
            IWomen* women = *iter;
            if (women->getType() == ENotMarry)
            {
                father->HandleMessage(women);
            }
            else if (women->getType() == EMarry)
            {
                husband->HandleMessage(women);    
            }
            else if (women->getType() == ENothusband)
            {
                son->HandleMessage(women);
            }
            else{}
            
            ++iter;
        }
    } 
    
private:
    QList<IWomen*> m_womens;
};

int main()
{
    Client client;
    client.request();
    
    return 0;
}

5. 代码分析

我们使用一个枚举来表示女性的不同状态
ENotMarry :未婚 ,EMarry:已婚,丈夫健在,ENothusband:丈夫去世。从整个设计上分析,有处理权的人(如父亲、丈夫、儿子)才是设计的核心,他们是要处理这些请求的。

6.设计问题

职责界定不清晰。女儿提出的请示,应该在父亲类中作出决定,把原本应该是父亲类做的事情抛给了其他类进行处理。
②代码臃肿。在 Client 中写了 if...else 的条件判断,随着处理该类型的请示人员越多,判断就越多。
③耦合过重。要根据Women 的 type 来决定使用 IHandler 的哪个实现类来处理请求。如果 IHandler 的实现类继续扩展,需要修改 Client 类,与开闭原则违背了。
④异常情况欠考虑。如果妻子向父亲请求指示,父亲应该如何处理,在程序上没有体现出来,逻辑失败了。

扫描二维码关注公众号,回复: 3410329 查看本文章

7.解决方法

女性提出一个请示,必然要获得一个答复,而且这个答案是唯一的,重新设计后,抽象这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就作出回应,如果女儿已经出嫁就把请求转发给女婿。父亲、丈夫、儿子每个节点有两个选择:要么作出回应,要么把请求转发到后续环节。
顺序处理图:16-2


示例三:妇女“三从”(改善设计)

1. 类图16-3


2. 类图说明:

三个实现类 Father、Husband、Son 只要实现构造函数和父类中的抽象方法 response 就可以了,具体由谁处理女性提出的请求,都已经转移到了 Handler 抽象类中。


3. 代码清单16-2

//////////////////    **********  2. 妇女“三从”改善设计,代码清单16-2:***************//

enum EType
{
    ENotMarry    = 1,
    EMarry          ,
    ENothusband
};

class IWomen
{
public:
    virtual int     getType()       = 0;      //获得个人状况
    virtual QString getRequest()    = 0;      //获得个人请示
};

class Women:public IWomen
{
public:
    Women(EType type, QString request)
    {
        this->m_type    = type;
        this->m_request = request;
    }
    virtual int getType()
    {
        return this->m_type;
    }
    virtual QString getRequest()
    {
        return this->m_request;
    }
    
private:
    EType   m_type;
    QString m_request;
};

class Handler
{
public:
    Handler(){}
    Handler(EType type)
    {
        this->m_type = type;
    }

    void    HandleMessage(IWomen *women)
    {
        if (women->getType() == this->m_type)
        {
            this->response(women);
        }
        else
        {
            if (this->m_nextHandler != nullptr)
            {
                this->m_nextHandler->HandleMessage(women);
            }
            else
            {
                qDebug() << "NO!";
            }
        }
    }
    void    setNext(Handler *handler)
    {
        this->m_nextHandler = handler;
    }
protected:
    virtual void    response(IWomen *women) = 0;
    
protected:
    EType       m_type;
    Handler     *m_nextHandler;
};

class Father:public Handler
{
public:
    Father()
    {
        this->m_type = ENotMarry;
    }

    virtual void    response(IWomen *women)
    {
        qDebug() << "request:" << women->getRequest();
        qDebug() << "Father restore: ...";
    }
};

class Husband:public Handler
{
public:
    Husband()
    {
        this->m_type = EMarry;
    }

    virtual void    response(IWomen *women)
    {
        qDebug() << "request: "<< women->getRequest();
        qDebug() << "Husband restore: ...";
    }
};

class Son:public Handler
{
public:
    Son()
    {
        this->m_type = ENothusband;
    }

    virtual void    response(IWomen *women)
    {
        qDebug() << "request: "<< women->getRequest();
        qDebug() << "Son restore: ...";
    }
};

class Client
{
public:
    Client()
    {
        QString request = "***";
        for (int i = 0; i < 5; ++i)
        {
            srand((unsigned)time(NULL)); 
            int num = rand() % (4 - 1) + 1;
            EType type = EType(num);
            IWomen* women = new Women(type, request);
            m_womens.push_back(women);
        }
    }
    void    request()
    {
        Handler *father    = new Father();
        Handler *husband   = new Husband();
        Handler *son       = new Son();
        father->setNext(husband);
        husband->setNext(son);
        
        QList<IWomen*>::ConstIterator iter = m_womens.begin();
        while(iter != m_womens.end())
        {
            IWomen* women = *iter;
            if (women->getType() == ENotMarry)
            {
                father->HandleMessage(women);
            }
            else if (women->getType() == EMarry)
            {
                husband->HandleMessage(women);    
            }
            else if (women->getType() == ENothusband)
            {
                son->HandleMessage(women);
            }
            else{}
            
            ++iter;
        }
    } 
    
private:
    QList<IWomen*> m_womens;
};

int main()
{
    Client client;
    client.request();
    
    return 0;
}

 

4. 代码分析

其实这里也用到模板方法模式,在模板方法中判断请求的类型和当前能够处理的类型,如果相同调用基本方法,作出反馈,如果不相等,则传递到下一个环节,由下一环节作出回应,如果已经达到环节尾部,则直接做不同意处理。基本方法 response 需要各个实现类实现,每个实现类只要实现两个职责:一是定义自己能够处理的等级级别;而是对请求作出回应。


四、责任链模式的应用


1. 优点:

将请求和处理分开。请求者可以不知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦,提高系统的灵活性。

2. 缺点:

①性能问题。每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
②调试不便。特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试时逻辑可能比较复杂。


3. 注意事项:

链中节点数量需要控制,避免出现超长链的情况,一般做法是在 Handler 中设置一个最大的节点数量,在 setNext 方法中判断是否已经是超过其阈值,超过则不允许建立该链,避免无意识地破坏系统性能。

五、最佳实践

  • 通过融合模板方法模式,各个实现类只要关注自己的业务逻辑就行,至于说什么事要自己处理,那就让父类去决定,也就是父类实现了请求传递的功能,子类实现请求的处理,各个实现类只能完成一个动作或逻辑,也就是只有一个原因引起类的改变。
  • 责任链模式屏蔽了请求的处理过程,当发起一个请求,谁处理可以不用关心,只要把请求抛给责任链的第一个矗立着,最终会返回一个处理结果(也可不处理),作为请求者可以不用知道到底是谁来处理的,这是责任链模式的核心。
  • 作为补救模式:例如一个请求(如银行存款币种),一个处理者(只处理人民币),随着业务发展,要增加矗立着数量和类型,这时只在第一个处理者后面建立一个链,也就是责任链来处理。这些都不用对原有的业务逻辑产生很大变化,通过扩展实现类就可以解决需求变更问题。

参考文献《秦小波. 设计模式之禅》(第2版) (华章原创精品) 机械工业出版社

猜你喜欢

转载自blog.csdn.net/Jecklin_online/article/details/82854810
今日推荐