Correct connection for multiple listeners who need to access shared state data

Working with the traditional listener callback function. I have several listeners collecting different things. Each material collected by the listener is inside the listener in internal structures.

The problem is that I want some of the listeners to know some things about the other listeners.

I follow the order in which the listeners are registered, so if I deliberately register events in a specific order, the later listener can be sure that the earlier listener has updated its stuff and somehow accessed it to do more things.

My first attempt is to have each listener store a reference to the listeners it depends on. So I register the listeners in the order of those without dependencies, with those with the previously registered dependencies, and then establish links between the listeners in various ways.

I am beginning to understand how bad it feels, and I was wondering how I was somehow along the way. What would be a more appropriate pattern when one student needs to access material in another?

Here's some pseudocode to illustrate:

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 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);
   }
 }
}

      

0


source to share


3 answers


Why not have a central object that will keep track of how many times the onEvent method has been fired for all listener classes



 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 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

      

+1


source


There are many combinations you describe here. Your best bet would be to eliminate all this dependency on the back channel, but otherwise, you might have those that have dependencies that are listening not on the first listener list, but on what they depend on. Or you can make them wait until they have all the signals.

You can automate dependency management by telling your listeners who they depend on. The listener list will not be ordered in order of insertion, but to ensure that dependent objects match their dependencies. Your listener interface will look something like this:

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

      



Or just links like:

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

      

+2


source


"How would we change that so that Listener B is aware of Listener A? Or didn't even know, somehow contacted?"

You don't often want to link two "peer" objects like this. You want your two peers to be dependent on something in common.

The deeper question is, what does listener A or listener B do with all the information they collect?

A The listener often does two things: it collects data and takes action. Often these two things need to be separated. Listeners need to listen and collect and do a little more. Some other objects can be activated by the listener.

You can only have one listener that has multiple actions (A and B). The listener can then provide the appropriate values ​​for A as well as B. It provides "a" counting to A. It provides "a" or "b" for B.

+1


source







All Articles