设计模式 笔记 责任链模式 chain of responsibility


//---------------------------15/04/25----------------------------


//Chain of responsibility 责任链-----对象行为型模式

/*

    1:意图:

        使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象

        连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

    2:动机:

    3:适用性:

        1>有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

        2>你想在不明确指定接受者的情况下,向多个对象中的一个 请求提交一个请求。

        3>可处理一个请求的对象集合应被动态指定。

    4:结构:

 

        Client-------------->Handler:<---------

                             successor---------|

                             HandleRequest(){ successor->HandleRequest()}

                                |

                        -------------------

                        |                 |

                    ConcreteHandler1:  ConcereteHandler2:

                    HandleRequest()    HandleRequest()

                    { if can handle

                      { do something}

                      else

                      { Handler::HandleRequest()}

                    }

    5:参与者:

        1>Handler

            1)定义一个处理请求的接口。

            2)(可选)实现后继链。

        2>ConcreteHandler

            1)处理它所负责的请求。

            2)可访问它的后继者。

            3)如果可处理该请求,就处理之;否则将该请求转发给它的后继者。

        3>Clinet

            向链上的具体处理者对象提交请求。

    6:协作:

        当客户提交一个请求时,请求沿着链传递直至有一个ConcreteHandler对象负责处理它。

    7:效果:

      优点:

        1>降低耦合度:

            该模式使得对象无需知道是其他哪一个对象处理其请求。接收者和发送者都没有对方的明确的

            信息,且链中的对象不需知道链的结构。

            所以责任链可简化对象的相互连接。

        2>增强了给对象指派职责的灵活性:

            可以在运行时刻动态增加或修改职责。

      缺点:

        1>不保证被接受。

            既然一个请求没有明确的就收者,那么不能保证一定会被处理。

        2>当链条太长时,会有效率问题(ps:这一点是我自己加的)

            和明确指派任务相比,这么做或多或少会损失点效率,所以不能乱用。

    8:实现:

        1>实现后继者链:

            1)定义新的链接:

                没有已有链接时只能自己定义了。

            2)使用已有的链接:

                如果已经有个链接了,比如说Composite模式中定义了Parent的引用。直接拿来用就行了

                也就是把父部件当作后继者,因为责任链一般都是向传递的,也就是越往越普通。

 

        2>链接后继者:

            如果是自己定义一个后继者链,Handler不仅要定义接口,通常也要维护链接。也就是要提供一个

            缺省实现:向后继者转发请求。

        3>表示请求:

            1)硬编码:

                也就是直接调用,这样只能表示一种请求类型。

            2)使用处理函数:

                通过传递参数来判断请求的类型。这就需要发送者和接收者在编码问题上达成一致。

    9:代码示例:                                                                     */

//定义了请求的类型

typedef int Topic;

const Topic NO_HELP_TOPIC = -1;


//Handler 定义了各种接口

class HelpHandler

{

public:

    HelpHandler(HelpHandler* = 0, Topic = NO_HELP_TOPIC);

    virtual bool HasHelp();

    virtual void SetHandler(HelpHandler*, Topic);

    virtual void HandleHelp();

    

private:

    HelpHandler* _successor;

    Topic _topic;

};


HelpHandler::HelpHandler(HelpHandler* h, Topic t)

    : _successor(h), _topic(t)  {}


bool HelpHandler::hasHelp()

{

    return _topic != NO_HELP_TOPIC;

}


//调用后继者的HandleHelp()

void HelpHandler::HandleHelp()

{

    if(_successor != 0)

        _successor->HandleHelp();

}


//ConcreteHandler中的abstract 听起来很奇怪,但是就是这样的

//很多东西都有帮助,窗口组件则一般都会有帮助,所以定义一个继承子Handlerabstract

//但是它确实也属于HandlerConcreteHandler类,因为它指定了是窗口组件类。

class Widget : public HelpHandler

{

protected:

    Widget(Widget* parent, Topic t = NO_HELP_TOPIC);

    

private:

    Widget* _parent;

};


Widget::Widget(Widget* w, Topic t) : HelpHandler(w, t)

{

    _parent = w;

}


//ConcreteHandler 具体的处理者。

class Button : public Widget

{

public:

    Button(Widget* d, Topic t = NO_HELP_TOPIC);

    virtual void HandleHelp();

};


Button::Button(Widget* h, Topic t) : Widget(h, t){}


//如果有帮助就调用,否则传递给后继者(如果有的话)

void Button::HandleHelp()

{

    if(HasHelp())

    {

        

        //do something

    }

    else

    {

        HelpHandler::HandleHelp();

    }

}


//ConcreteHandler:类似上面,只不过它后继者可以是任意的帮助类,而不一定只是窗口类

class Dialog : public Widget

{

public:

    Dialog(HelpHandler* h, Topic = NO_HELP_TOPIC);

    virtual void HandleHelp();

};


Dialog::Dialog(HelpHandler* h, Topic t) : Widget(0)

{

    SetHandler(h, t);

}


void Dialog::HandleHelp()

{

    if(HasHelp())

    {

        //do something

    }

    else

    {

        HelpHandler::HandleHelp();

    }

}


//ConcreteHandler:最后一个节点,没有后继者了。

class Application : public HelpHandler

{

    Application(Topic t) : HelpHandler(0, t){}

    virtual void HandleHelp();

};


void Application::HandleHelp()

{

    //do something

}



const Topic PRINT_TOPIC = 1;

const Topic PAPER_ORIENTATION_TOPIC = 2;

const Topic APPLICATION_TOPIC = 3;


Application* application = new Application(APPLICATION_TOPIC);

Dialog* dialog = new Dialog(application, PRINT_TOPIC);

Button* button = new Button(dialog, PAPER_ORIENTATION_TOPIC);


//这里Button有自己的帮助(PAPER_ORIENTATION_TOPIC)所以会自己处理,并不会交给后继者

//当然如果里面的do something中调用了Handler::HandlerHelp(),那么还是会传递下去的。

button->HandleHelp();




posted @ 2015-04-25 14:14  boydfd  阅读(211)  评论(0编辑  收藏  举报