Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 以观察者模式(C+;+;)向视图中大量发送更新请求问题_C++_Model View Controller_Observer Pattern - Fatal编程技术网

C++ 以观察者模式(C+;+;)向视图中大量发送更新请求问题

C++ 以观察者模式(C+;+;)向视图中大量发送更新请求问题,c++,model-view-controller,observer-pattern,C++,Model View Controller,Observer Pattern,我有一些MVC代码,它使用观察者模式,如下所示: void Model::ChangeMethod1() { m_A = m_A + 1; ... Notify(); } void Model::ChangeMethod2() { m_A = m_A + 2; ... Notify(); } void Model::ChangeMethod3() { ChangeMethod1(); ChangeMethod2(); N

我有一些MVC代码,它使用观察者模式,如下所示:

void Model::ChangeMethod1()
{
    m_A = m_A + 1;
    ...
    Notify();
}

void Model::ChangeMethod2()
{
    m_A = m_A + 2;
    ...
    Notify();
}

void Model::ChangeMethod3()
{
    ChangeMethod1();
    ChangeMethod2();
    Notify();
}

void Model::ChangeMethod4()
{
    ChangeMethod1();
    ChangeMethod2();
    ChangeMethod3();
    Notify();
}
有许多函数,如
ChangeMethodX
,它们将对模型进行更改,并通知查看者,当查看者收到事件时,它们将刷新/更新自己

您可以看到,每个函数
ChangeMethodX
都有一个Notify()函数,它在内部向观察者发送事件

但是我不希望观察者在每个函数中接收太多的事件,因为会有太多的事件,我希望每个顶级函数调用无论是否有任何内部函数调用都只向查看器发送一个更新事件


我认为这是在很多情况下都会发生的一个非常常见的问题,比如MVC模式,因为模型会通知观众进行更新。但是,如果模型在顶级函数调用中多次更改,我们必须避免淹没事件。

我想到了两种可能的方法:

如果受试者完全在您的控制下,并且此解决方案不太具有侵入性,则可以添加一个可选参数,指定调用的
ChangeMethodX
是否为顶级函数,如下所示:

void Model::ChangeMethod1(bool topLevel = true)
{
    m_A = m_A + 1;
    ...
    NotifyIfTopLevel(topLevel);
}

void Model::ChangeMethod2(bool topLevel = true)
{
    m_A = m_A + 2;
    ...
    NotifyIfTopLevel(topLevel);
}

void Model::ChangeMethod3(bool topLevel = true)
{
    ChangeMethod1(false);
    ChangeMethod2(false);
    NotifyIfTopLevel(topLevel);
}

void Model::ChangeMethod4(bool topLevel = true)
{
    ChangeMethod1(false);
    ChangeMethod2(false);
    ChangeMethod3(false);
    NotifyIfTopLevel(topLevel);
}

void Model::NotifyIfTopLevel(bool topLevel)
{
    if (topLevel)
        Notify();
}
然而,它在大多数情况下是丑陋的,它可能会弄脏你的界面


另一方面,如果必须处理并发性,那么您可以选择的第二种方法是有风险的。此外,如果捕获到异常并进行处理,则必须记住将对象恢复到正确状态(
正在更改--
如果尚未调用),否则观察者将不再接收通知

int is_changing = 0;

void Model::ChangeMethod1()
{
    m_A = m_A + 1;
    ...
    NotifyIfNotChanging();
}

void Model::ChangeMethod2()
{
    m_A = m_A + 2;
    ...
    NotifyIfNotChanging();
}

void Model::ChangeMethod3()
{
    is_changing++;
    ChangeMethod1();
    ChangeMethod2();
    is_changing--;
    NotifyIfNotChanging();
}

void Model::ChangeMethod4()
{
    is_changing++;
    ChangeMethod1();
    ChangeMethod2();
    ChangeMethod3();
    is_changing--;
    NotifyIfNotChanging();
}

void Model::NotifyIfNotChanging()
{
    if (is_changing == 0)
        Notify();
}

如果您有许多<代码> ChangeMethodX < /C>方法,可以考虑使用面向方面的框架来分离通知观察员的关注。特别是如果您需要重复

正在改变+++
/
--
或简单的
通知调用,将它们移动到适当的方面类中肯定会更具可读性


编辑

至于RAII方法,我认为它在这里被过度使用了,因为您没有资源来释放、创建和处理对象,每次都是为了满足您的需求而过度使用。 顺便说一句,如果您想遵循这条路径,那么我建议您修复一些代码气味

  • 您没有正确封装
    SetTopLevelCall
    。它不应该是
    公共的
    ,因为类的用户不能弄乱它
  • 有一个新的公共类
    delferredeventsender
    ,它与您的
    模型
    类紧密耦合。最糟糕的是它负责
    Notify
    方法,该方法应该由
    模型本身调用。此外,您排除了需要访问
    模型
    专用字段和函数的可能性
  • 下面是我将如何面对这些问题,即使它还不完美

    class Model
    {
        public:
            Model()
            {
            }
        
            ~Model()
            {
            }
        
            void ChangeMethod1();
            void ChangeMethod2();
            void ChangeMethod3();
            void ChangeMethod4();
        
            void Notify();
        
        protected:
        
            class DeferredEventSender
            {
                public:
                
                    DeferredEventSender(Model* m)
                    {
                        _m = m;
                        doCallNotify = _m->topLevel;
                        _m->topLevel = false;
                    }
                
                    ~DeferredEventSender()
                    {
                        if (doCallNotify)
                        {
                            _m->Notify();
                            _m->topLevel = true;
                        }
                    }
                    
                    Model* _m;
                    bool doCallNotify;
            };
        
            bool topLevel = true;
        
            int m_A;
            int m_B;
    };
    
    
    void Model::ChangeMethod1()
    {
        Model::DeferredEventSender sender(this);
        m_A = m_A + 1;
    }
    
    ...
    

    我只是按照Marco Luzzara的第二种方法,创建一个简单的演示C++代码,见下面:

    第1版:

    #include <iostream>
    using namespace std;
    
    class Model
    {
    public:
        Model()
            : m_TopLevelCallScope(false)
        {
        }
    
        ~Model()
        {
        }
    
        void ChangeMethod1();
        void ChangeMethod2();
        void ChangeMethod3();
        void ChangeMethod4();
    
        void Notify();
    
        bool IsTopLevelCall()
        {
            return m_TopLevelCallScope;
        }
    
        void SetTopLevelCall(bool topLevel)
        {
            m_TopLevelCallScope = topLevel;
        }
    
    private:
    
        // if this variable is true, it means a top level call scope is entered
        // then all the inner call should not send event, the final event could
        // send when the top level sender get destructed
        bool m_TopLevelCallScope;
    
        // other members
        int m_A;
        int m_B;
    };
    
    
    // this is a deferred notification
    // each function should create a local object
    // but only the top level object can finally send a notification
    class DeferredEventSender
    {
    public:
    
        DeferredEventSender(Model* model)
            : m_Model(model)
        {
            if(m_Model->IsTopLevelCall() == false)
            {
                m_Model->SetTopLevelCall(true);
                m_TopLevelCallScope = true;
            }
            else
            {
                m_TopLevelCallScope = false;
            }
        }
    
        ~DeferredEventSender()
        {
            if (m_TopLevelCallScope == true)
            {
                // we are exiting the top level call, so restore it to false
                // it's time to send the notification now
                m_Model->SetTopLevelCall(false);
                m_Model->Notify();
            }
            // do nothing if m_TopLevelCallScope == false
            // because this means we are in a inner function call
        }
        bool m_TopLevelCallScope;
        Model* m_Model;
    };
    
    
    
    void Model::ChangeMethod1()
    {
        DeferredEventSender sender(this);
        m_A = m_A + 1;
    }
    
    void Model::ChangeMethod2()
    {
        DeferredEventSender sender(this);
        m_A = m_A + 2;
    }
    
    void Model::ChangeMethod3()
    {
        DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
    }
    
    void Model::ChangeMethod4()
    {
        DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
        ChangeMethod3();
    }
    
    void Model::Notify()
    {
        cout << "Send event!" << endl;
    }
    
    int main()
    {
        Model m;
    
        m.ChangeMethod1();
    
        m.ChangeMethod2();
    
        m.ChangeMethod3();
    
        m.ChangeMethod4();
    
        return 0;
    }
    
    #include <iostream>
    using namespace std;
    
    class Model
    {
        public:
            Model()
            {
            }
    
            ~Model()
            {
            }
    
            void ChangeMethod1();
            void ChangeMethod2();
            void ChangeMethod3();
            void ChangeMethod4();
    
            void Notify();
    
        protected:
    
            class DeferredEventSender
            {
                public:
    
                    DeferredEventSender(Model* m)
                    {
                        m_Model = m;
    
                        // the first instance of the DeferredEventSender will copy the status of m_TopLevel
                        // and all the later(inner) instances will have false m_TopLevel
                        m_DoCallNotify = m_Model->m_TopLevel;
                        m_Model->m_TopLevel = false;
                    }
    
                    ~DeferredEventSender()
                    {
                        // we only call Notify on the top level DeferredEventSender
                        if (m_DoCallNotify)
                        {
                            m_Model->Notify();
                            m_Model->m_TopLevel = true;
                        }
                    }
    
                    Model* m_Model;
                    bool m_DoCallNotify;
            };
    
            bool m_TopLevel = true;
    
            int m_A;
            int m_B;
    };
    
    
    void Model::ChangeMethod1()
    {
        Model::DeferredEventSender sender(this);
        m_A = m_A + 1;
    }
    
    void Model::ChangeMethod2()
    {
        Model::DeferredEventSender sender(this);
        m_A = m_A + 2;
    }
    
    void Model::ChangeMethod3()
    {
        Model::DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
    }
    
    void Model::ChangeMethod4()
    {
        Model::DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
        ChangeMethod3();
    }
    
    void Model::Notify()
    {
        cout << "Send event!" << endl;
    }
    
    int main()
    {
        Model m;
    
        m.ChangeMethod1();
    
        m.ChangeMethod2();
    
        m.ChangeMethod3();
    
        m.ChangeMethod4();
    
        return 0;
    }
    
    
    您可以看到,在main()函数中,我只有4个函数调用,只有4个事件被发送

    我使用的方法是在每个
    ChangeMethodX
    方法中放置一个
    DeferredEventSender
    本地对象,如果它是顶级函数调用,该对象将其成员变量
    m_TopLevelCallScope
    设置为true,如果它是内部函数调用,
    m_TopLevelCallScope
    设置为false

    DeferredEventSender
    本地对象离开作用域时,它将检查它是否是顶级对象,如果为true,它将发送事件,因此所有内部函数调用都不会发送事件

    演示代码可以扩展,这样事件就可以累积并存储在
    DeferredEventSender
    对象或
    Model
    对象中的
    std::queue
    中,当顶部的
    DeferredEventSender
    对象被销毁时,我们可以在
    std::queue
    中运行一个过滤器,并删除重复的事件,发送我们真正需要的事件


    根据Marco Luzzara的建议,这是修改版,谢谢Marco Luzzara

    第2版:

    #include <iostream>
    using namespace std;
    
    class Model
    {
    public:
        Model()
            : m_TopLevelCallScope(false)
        {
        }
    
        ~Model()
        {
        }
    
        void ChangeMethod1();
        void ChangeMethod2();
        void ChangeMethod3();
        void ChangeMethod4();
    
        void Notify();
    
        bool IsTopLevelCall()
        {
            return m_TopLevelCallScope;
        }
    
        void SetTopLevelCall(bool topLevel)
        {
            m_TopLevelCallScope = topLevel;
        }
    
    private:
    
        // if this variable is true, it means a top level call scope is entered
        // then all the inner call should not send event, the final event could
        // send when the top level sender get destructed
        bool m_TopLevelCallScope;
    
        // other members
        int m_A;
        int m_B;
    };
    
    
    // this is a deferred notification
    // each function should create a local object
    // but only the top level object can finally send a notification
    class DeferredEventSender
    {
    public:
    
        DeferredEventSender(Model* model)
            : m_Model(model)
        {
            if(m_Model->IsTopLevelCall() == false)
            {
                m_Model->SetTopLevelCall(true);
                m_TopLevelCallScope = true;
            }
            else
            {
                m_TopLevelCallScope = false;
            }
        }
    
        ~DeferredEventSender()
        {
            if (m_TopLevelCallScope == true)
            {
                // we are exiting the top level call, so restore it to false
                // it's time to send the notification now
                m_Model->SetTopLevelCall(false);
                m_Model->Notify();
            }
            // do nothing if m_TopLevelCallScope == false
            // because this means we are in a inner function call
        }
        bool m_TopLevelCallScope;
        Model* m_Model;
    };
    
    
    
    void Model::ChangeMethod1()
    {
        DeferredEventSender sender(this);
        m_A = m_A + 1;
    }
    
    void Model::ChangeMethod2()
    {
        DeferredEventSender sender(this);
        m_A = m_A + 2;
    }
    
    void Model::ChangeMethod3()
    {
        DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
    }
    
    void Model::ChangeMethod4()
    {
        DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
        ChangeMethod3();
    }
    
    void Model::Notify()
    {
        cout << "Send event!" << endl;
    }
    
    int main()
    {
        Model m;
    
        m.ChangeMethod1();
    
        m.ChangeMethod2();
    
        m.ChangeMethod3();
    
        m.ChangeMethod4();
    
        return 0;
    }
    
    #include <iostream>
    using namespace std;
    
    class Model
    {
        public:
            Model()
            {
            }
    
            ~Model()
            {
            }
    
            void ChangeMethod1();
            void ChangeMethod2();
            void ChangeMethod3();
            void ChangeMethod4();
    
            void Notify();
    
        protected:
    
            class DeferredEventSender
            {
                public:
    
                    DeferredEventSender(Model* m)
                    {
                        m_Model = m;
    
                        // the first instance of the DeferredEventSender will copy the status of m_TopLevel
                        // and all the later(inner) instances will have false m_TopLevel
                        m_DoCallNotify = m_Model->m_TopLevel;
                        m_Model->m_TopLevel = false;
                    }
    
                    ~DeferredEventSender()
                    {
                        // we only call Notify on the top level DeferredEventSender
                        if (m_DoCallNotify)
                        {
                            m_Model->Notify();
                            m_Model->m_TopLevel = true;
                        }
                    }
    
                    Model* m_Model;
                    bool m_DoCallNotify;
            };
    
            bool m_TopLevel = true;
    
            int m_A;
            int m_B;
    };
    
    
    void Model::ChangeMethod1()
    {
        Model::DeferredEventSender sender(this);
        m_A = m_A + 1;
    }
    
    void Model::ChangeMethod2()
    {
        Model::DeferredEventSender sender(this);
        m_A = m_A + 2;
    }
    
    void Model::ChangeMethod3()
    {
        Model::DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
    }
    
    void Model::ChangeMethod4()
    {
        Model::DeferredEventSender sender(this);
        ChangeMethod1();
        ChangeMethod2();
        ChangeMethod3();
    }
    
    void Model::Notify()
    {
        cout << "Send event!" << endl;
    }
    
    int main()
    {
        Model m;
    
        m.ChangeMethod1();
    
        m.ChangeMethod2();
    
        m.ChangeMethod3();
    
        m.ChangeMethod4();
    
        return 0;
    }
    
    
    #包括
    使用名称空间std;
    类模型
    {
    公众:
    模型()
    {
    }
    ~Model()
    {
    }
    void ChangeMethod1();
    void changethod2();
    void changethod3();
    void changethod4();
    无效通知();
    受保护的:
    类延迟事件检测器
    {
    公众:
    延时通风机(型号*m)
    {
    m_模型=m;
    //DeferredEventSender的第一个实例将复制m_TopLevel的状态
    //所有后面的(内部)实例都将具有假m_TopLevel
    m_DoCallNotify=m_模型->m_顶层;
    m_Model->m_TopLevel=false;
    }
    ~DeferredEventSender()
    {
    //我们只在最高级的DeferredEventSender上调用Notify
    如果(m_DoCallNotify)
    {
    m_Model->Notify();
    m_Model->m_TopLevel=true;
    }
    }
    模型*m_模型;
    bool m_DoCallNotify;
    };
    bool m_TopLevel=真;
    国际货币基金组织;
    国际货币基金组织;
    };
    void模型::ChangeMethod1()
    {
    Model::DeferredEventSender发送器(此);
    m_A=m_A+1;
    }
    void模型::ChangeMethod2()
    {
    Model::DeferredEventSender发送器(此);
    m_A=m_A+2;
    }
    void模型::ChangeMethod3()
    {
    Model::DeferredEventSender发送器(此);
    方法1();
    方法2();
    }
    void模型::ChangeMethod4()
    {
    Model::DeferredEventSender发送器(此);
    方法1();
    方法2();