【问题标题】:How to avoid infinite loop in Observer pattern?如何避免观察者模式中的无限循环?
【发布时间】:2019-02-26 17:17:59
【问题描述】:

我只有一个有很多实例的类。每个实例都是其他几个实例的观察者。同样,每个实例都可以被其他几个实例观察到。

如何避免观察者调用update()的无限循环?

【问题讨论】:

    标签: java design-patterns


    【解决方案1】:

    如果你的系统是单线程的,那么你只需要在你的 notify 方法中设置一个守卫:

    private boolean _notifying;
    
    public void notify() {
      if(_notifying) {
        return;
      }
      _notifying = true;
      try {
        // ... do notifying here...
      } finally {
        _notifying = false;
      }
    }
    

    【讨论】:

      【解决方案2】:

      您正在寻找的是一种检测循环的图遍历算法。一种简单的方法(仅适用于单线程场景)是保留一个全局/静态计数器,让每个顶级 update() 调用获得一个唯一标识符。然后每个观察者跟踪它是否已经用给定的标识符(ID)处理了更新,在这种情况下忽略它。这意味着您的 update 方法必须使用带有特定更新 ID 号的参数进行扩展。

      【讨论】:

        【解决方案3】:

        好吧,如果您正在定义“事件”对象,您可能会向其中添加已经处理过事件的对象。在这种情况下,如果您关闭循环,您可以退出。在伪代码中

        eventFired(Event e)
          if (e.hasBeenEvaluatedBy(this)){
            return;
          }
          e.addEvaluator(this);
        
          // Do magic
        
          refire(e);
        }
        

        在这种情况下,我们会得到类似的结果: * A 开火。 * B 处理它并将自己添加到列表中 * B 重新触发 * C 处理事件并将自己添加到列表中 * C 重新触发 * A 处理事件并将自己添加到列表中 * 重新触发 * B 捕捉到事件,但已经在列表中。没有重发,无限循环被打破

        可以使用 ID 代替指针来避免垃圾收集问题

        【讨论】:

        • 我认为在事件中存储访问节点列表是个坏主意。有恒定数量的节点创建一次。并且存储(即列表或集合)在其中创建一次。但是每时每刻都有很多新事件。并且每时每刻都应该创建许多新列表。
        【解决方案4】:

        让您的观察者将接收到的事件(或其 ID)添加到某个临时存储中,并在收到每个新事件时让他们验证是否将相同的事件保存在存储中。如果是,那么他们不应该处理它。

        但是,如果我们尝试解决问题而不是找到合适的解决方法,那么:您的问题是对象 A 可以侦听对象 B,而对象 B 可以同时侦听对象 A(也许有一些中介对象)。恕我直言,这是一个糟糕的设计。

        观察者应该用来松耦合,让对象A知道对象B,反之则不然。

        如果您的对象 A 和 B 都相互了解,那么我不明白您为什么需要使用观察者。

        【讨论】:

        • 我不能告诉任何不知道域的事情。我可能不喜欢用 oop 方法来实现图(即我会创建类 Graph 并在其中使用简单的二维数组作为邻接矩阵)。使用这种方法可以更轻松地实现标准图形算法(至少对我而言)。
        • 也许你告诉我们你要做什么?
        • 如果你无法描述它,你将如何开发它? :))
        【解决方案5】:

        一种方法是仅在实际更新某些内容时才触发诸如更新之类的事件。 这种方法的好处是您通常可以减少触发的事件数量(减少工作)并简化代码。 例如

        final Set<String> set = ...
        
        public void onAdded(String string) {
           // is only added once.
           if (set.add(string)) {
               // only notifies once no matter how many times onAdded is 
               // called for this string, recursively or not.
               notifyAdded(string);
           }
        }
        

        【讨论】:

        • 如果两个对象试图使自己适应另一个对象的变化,但这样做的方式相互矛盾,这可能会失败。例如,当 CheckBox1 发生变化时,它会通知 CheckBox2,后者会更改其状态以匹配 CheckBox1。当 CheckBox2 发生变化时,它通知 CheckBox1,CheckBox1 将其状态更改为与 CheckBox2 相对。任一通知本身都可以,但它们一起强制执行无限循环(也可能是无限递归)。
        • 状态变化在这里并不重要。只有事件,这只允许一个事件传播一次(这本身可能是不受欢迎的)但是它不能重复一次以上。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多