适合需要访问共享状态数据的多个侦听器的耦合

时间:2008-11-09 00:56:42

标签: java design-patterns listener

使用传统的侦听器回调模型。我有几个收集各种东西的听众。每个听众收集的东西都在内部结构的监听器内。

问题是我想让一些听众知道其他听众中的一些“东西”。

我强制执行监听器注册顺序,所以如果我故意按某种顺序注册事件,以后的监听器可以确保先前的监听器更新其内容并以某种方式访问​​它以执行更多操作。

我的第一次尝试是让每个监听器存储对它所依赖的监听器的引用。因此,我按照那些没有依赖关系的方式将侦听器注册到具有先前注册的依赖关系的侦听器,然后在各种方法中设置侦听器之间的引用。

我开始意识到这种感觉有多糟糕,我想知道以前是不是已经走了这条路。当其中一个听众需要访问另一个人的东西时会有什么更合适的模式?

这是一些伪代码来说明:

interface Listener { onEvent(char e); }

class A implements Listener {
  private int count;
  public void onEvent(char  e) { if(e == 'a') count++; }
  public int getCount() { return count; }
}

class B implements Listener {
 private int count;
 // private A a;
 // private void setA(A a) { this.a = a; }

 public void onEvent(char  e) { if(e == 'b') count++; }
 public int getCount() { return count; }
 public int getAPlusBCount() {
   // We know B count, but we don't know A so how would we change this 
   // so B is A aware? Or not even aware, just somehow coupled? This
   // is the question
   // return a.getCount() + count;
 }

 public void doConditionalHere() {
  // Do some condition in B that relies on the state of data in A
  int acount = 0; // a.getCount(); ???
  if(acount % 2 == 0) {
   this.count--;
  }
 }
}

class Run {
 A a = new A();
 B b = new B();
 List listeners = new List();
 listeners.add(a);
 listeners.add(b);

 // The ugly way I add coupling right now is to keep a reference to A
 // inside B. It's commented out because I am hoping there is a more intelligent approach
 // b.setA(a);

 for(char c : "ababbabab") {
   for(listener : listeners) {
     listener.onEvent(c);
   }
 }
}

3 个答案:

答案 0 :(得分:2)

你在这里描述了很多耦合。最好的方法是消除所有这些反向通道的依赖关系,但是如果失败的话,也许你可能让那些依赖关系的人不是在初始的监听器列表上,而是在他们所依赖的任何东西上。或者你可以让他们等到他们拥有所有信号。

您可以通过让侦听器识别他们所依赖的人来自动化依赖关系管理。侦听器列表不是按插入顺序排序,而是为了确保依赖对象遵循其依赖性。你的监听器界面看起来像这样:

interface Listener {
  String getId();
  Collection<String> getDependencies();
  onEvent(char e);
}

或者只是引用,如下:

interface Listener {
  Collection<Listener> getDependencies();
  onEvent(char e);
}

答案 1 :(得分:1)

“我们如何改变这一点,以便侦听器B能够听到侦听器?或者甚至不知道,只是以某种方式耦合?”

你不经常想要像这样结合两个“对等”对象。你希望两个同伴依赖于共同点。

更深层次的问题是听众A或听众B对他们收集的所有信息做了什么?

监听器经常做两件事:它收集数据并采取行动。通常这两件事情需要分开。听众应该倾听并收集并做更多的事情。其他一些对象可以由监听器激活。

你可能只有一个听众,它有几个动作(A和B)。然后,听者可以向A和B提供适当的计数。它向A提供'a'计数。它向B提供'a'或'b'计数。

答案 2 :(得分:1)

为什么没有一个中心对象来跟踪为所有侦听器类触发onEvent方法的次数

 public interface CountObserver {

 public void updateCount(String className);
 public int getCount(String className);
}

public class CentralObserver implements CountObserver {

 private int aCount;
 private int bCount;

 public void updateCount(String className) {

 //There's probably a better way to do this than using
 //all these if-elses, but you'll get the idea.

  if (className.equals("AclassName")) {
   aCount++;
  }
  else if (className.equals("BclassName")) {
   bCount++;
  }
 }

 public int getCount(String className) {

  if (className.equals("AclassName")) {
   return aCount;
  }
  else if (className.equals("BclassName")) {
   return bCount;
  }
}

class A implements Listener {

 CountObserver countObserver;

 public void registerObserver (CountObserver countObserver) {

  this.countObserver = countObserver;
 }

 public void onEvent(char e) {

  if(e == 'a') {

   countObserver.updateCount (this.getClass.getName);
  }
 }

}

//Same thing for B or any other class implementing Listener. Your Listener interface should, of 

//course, have a method signature for the registerObserver method which all the listener classes 

//will implement.

class Run {

 private A a;
 private B b; 
 private CountObserver centralObserver;

 public runProgram () {

  centralObserver = new CentralObserver();
  a.registerObserver(centralObserver);
  b.registerObserver(centralObserver);

 //run OnEvent method for A a couple of times, then for B

 }

 public int getAcount () {

 return centralObserver.getCount(a.getClass.getName());
 }

 public int getBcount () {

 return centralObserver.getCount(b.getClass.getName());
 }
} 
 //To get the sum of all the counts just call getAcount + getBcount. Of course, you can always  add more listeners and more getXCount methods