Acoplamiento adecuado para múltiples oyentes que necesitan acceder a datos de estado compartidos

StackOverflow https://stackoverflow.com/questions/275456

  •  07-07-2019
  •  | 
  •  

Pregunta

Trabajar con un modelo de devolución de llamada de escucha tradicional. Tengo varios oyentes que recopilan varias cosas. Las cosas recopiladas de cada oyente están dentro del oyente en estructuras internas.

El problema es que quiero que algunos de los oyentes estén al tanto de algunas de las "cosas". en los otros oyentes.

Hago cumplir el orden de registro del oyente, por lo que si a sabiendas registro eventos en algún orden, un oyente posterior puede estar seguro de que un oyente anterior actualizó sus cosas y de alguna manera acceder a ellas para hacer más cosas.

Mi primer intento es hacer que cada oyente almacene una referencia a los oyentes de los que depende. Así que registro a los oyentes en el orden de aquellos sin dependencias de aquellos con dependencias registradas previamente, y luego establezco las referencias entre los oyentes en varios métodos.

Estoy empezando a darme cuenta de lo mal que se siente esto y me preguntaba si de alguna manera había pasado por este camino antes. ¿Cuál sería un patrón más apropiado cuando uno de los oyentes necesita acceder a cosas en otro?

Aquí hay algunos pseudocódigos para ilustrar:

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);
   }
 }
}
¿Fue útil?

Solución

¿Por qué no tener un objeto central que haga un seguimiento de cuántas veces se activó el método onEvent para todas las clases de oyentes?

 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

Otros consejos

Has descrito mucho acoplamiento aquí. Lo mejor sería eliminar toda esta dependencia del canal posterior, pero si no es así, es posible que las personas con dependencias escuchen no en la lista de escucha inicial, sino en lo que sea que dependan. O puede hacer que esperen hasta que tengan todas las señales.

Puede automatizar la gestión de dependencias haciendo que los oyentes identifiquen de quién dependen. La lista de oyentes se ordenaría no por orden de inserción, sino para asegurar que los objetos dependientes sigan su dependencia. Su interfaz de escucha se vería así:

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

O simplemente tenga las referencias, así:

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

" ¿Cómo cambiaríamos esto para que el oyente B sea el oyente A consciente? ¿O ni siquiera lo sabe, solo de alguna manera acoplado? ''

A menudo no quieres unir dos '' pares '' objetos como este. Desea que dos pares dependan de algo común.

La pregunta más profunda es ¿qué hace el oyente A o el oyente B con toda la información que recopilan?

Un oyente a menudo hace dos cosas: recolecta datos y toma medidas. A menudo, estas dos cosas necesitan ser separadas. Los oyentes deben escuchar y recopilar y hacer poco más. Un oyente puede activar otros objetos.

Lo que puede tener es un solo oyente que tiene varias acciones (A y B). El oyente puede proporcionar conteos apropiados para A y para B. Proporciona un conteo 'a' para A. Proporciona un conteo 'a' o 'b' para B.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top