zoukankan      html  css  js  c++  java
  • 设计模式 笔记 责任链模式 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();




  • 相关阅读:
    springboot 项目部署到服务器
    Thymeleaf的注意项
    springboot定时器
    springboot
    随笔
    mysql数据库连接超过8小时失效的解决方案(springboot)
    Druid连接池与spring配置
    IDEA快捷键
    jsonp解决跨域,用div,css,js,jq实现textarea自适应高度
    mysql的查询、子查询及连接查询(商城查询常用)
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983125.html
Copyright © 2011-2022 走看看