【问题标题】:How to implement specialized event handlers?如何实现专门的事件处理程序?
【发布时间】:2012-09-21 07:26:14
【问题描述】:

我正在为状态机表示编写一个图表编辑器应用程序。我有两个在画布和图表上操作的交互工具。第一个称为“编辑工具”,负责创建新的图表元素,例如节点和边。第二个称为“移动工具”,作用于图表布局,id est,它移动节点并更新边缘。这是简化的解释,但我不需要给你更多细节来问我的问题。

我想知道处理事件并将它们分发到工具中的最有效和最有组织的方式是什么

我知道我可以简单地拦截他们调用的事件并根据所选工具、当前状态和目标对象进行一些处理,但是这样代码会扩展到巨大的if (...) else if (...) 块、上下文标志等;并且变得非常难以维护。

对于这种情况是否有任何常见的代码模式?你能举一些例子吗?我可以查看哪些开源项目以了解更多信息?

【问题讨论】:

    标签: design-patterns event-handling application-design


    【解决方案1】:

    我不完全确定你的问题是否正确。通过阅读问题,您似乎正在寻找 observer 设计模式。但是,您对自己问题的回答并不真正符合这种解释......

    如果你想要,例如每次更改状态机时您的 UI 都会更新,那么您可能想查看 WikipediaCodeProject 的观察者模式,或者只是 google 一下。它是最常见的设计模式之一,如果您不了解它,绝对应该花几分钟时间熟悉它。

    作为如何将此模式应用于您的域的示例,假设您希望您的 LayoutManager 在用户使用编辑工具添加或删除节点/边时重新绘制图表。您不想直接从编辑工具中调用 LayoutManager,因为这会强烈地couple 这两个组件。因此,您可以按如下方式指定观察者接口(我在这里使用 C++,因为我不知道您的应用程序是用什么语言编写的):

    class StateMachineModelObserver
    {
    public:
       virtual void nodeChanged(Node* n)=0;
       virtual void edgeChanged(Edge* e)=0;
    };
    

    让任何想要在状态机模型更改时收到通知的主体都从该类继承并实现其功能。例如:

    class MyStateMachineLayoutManager : public StateMachineModelObserver
    {
    public:
       void foo() {} // these are 
       void bar() {} other functions of the layout manager
    
       virtual void nodeChanged(Node* n)
       {
          redraw();
       }
    
       virtual void edgeChanged(Edge* e)
       {
          redraw();
       }
    };
    

    现在您需要您的状态机模型提供允许订阅和取消订阅通知的功能,并且您需要发送通知。

    class MyStateMachineModel
    {
    public:
       Node* addNode()
       {
          Node* n=new Node();
          insertNodeIntoModel();
          notify(n);
          return n;
       }
    
       void subscribe(StateMachineModelObserver* o)
       {
          m_mutex.lock();
          m_observers.insert(o);
          m_mutex.unlock();
       }
    
       void unsubscribe(StateMachineModelObserver* o)
       {
          m_mutex.lock();
          m_observers.insert(o);
          m_mutex.unlock();
       }
    
    private:
       void notify(Node* n)
       {
          m_mutex.lock();
          for_each(m_observers.begin(), m_observers.end(),
             [](StateMachineModelObserver* o)
             {
                o->nodeChanged(n);
             }
          );
          m_mutex.unlock();
       }
    
       std::set<StateMachineModelObserver*> m_observers;
       std::mutex m_mutex;
    };
    

    现在您所要做的就是将 LayoutManager 订阅到状态机模型,并且每次模型更改(这里:正在添加一个节点)时,它都会自动收到通知。您可以为不同的通知设置不同的观察者接口,也可以为不同类型的通知设置一个具有不同功能的观察者接口。

    【讨论】:

      【解决方案2】:

      我刚刚发现了一篇非常好的文章,描述了可以使用状态机进行操作的 GUI 设计:http://lassala.net/2008/02/05/state-machines-and-gui-interaction-part-i/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-15
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 2020-02-07
        相关资源
        最近更新 更多