Couplage correct pour plusieurs écouteurs ayant besoin d'accéder à des données d'état partagées

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

  •  07-07-2019
  •  | 
  •  

Question

Utilisation d'un modèle de rappel d'écoute traditionnel. J'ai plusieurs auditeurs qui collectionnent des trucs divers. Les éléments collectés par chaque auditeur sont à l'intérieur de l'écouteur dans des structures internes.

Le problème est que je veux que certains auditeurs soient au courant de certains "trucs" dans les autres auditeurs.

J'applique l'ordre d'enregistrement des auditeurs. Par conséquent, si j'inscris sciemment les événements dans un ordre, un auditeur ultérieur peut être sûr qu'un auditeur précédent a mis à jour ses données et y a accès pour en faire davantage.

Ma première tentative consiste à faire en sorte que chaque auditeur stocke une référence aux écouteurs dont il dépend. J'inscris donc les écouteurs dans l'ordre de ceux qui n'ont pas de dépendances avec ceux ayant des dépendances préalablement enregistrées, puis je règle les références entre les écouteurs selon diverses méthodes.

Je commence à comprendre à quel point cela se sent et je me demandais si cela avait déjà été fait auparavant. Quel serait un modèle plus approprié lorsqu'un des auditeurs doit avoir accès à des contenus dans un autre?

Voici un pseudocode à illustrer:

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);
   }
 }
}
Était-ce utile?

La solution

Pourquoi ne pas avoir un objet central qui garde la trace du nombre de fois où la méthode onEvent a été déclenchée pour toutes les classes d'écouteur

 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

Autres conseils

Vous avez décrit beaucoup de couplage ici. Le mieux serait d'éliminer toute cette dépendance de canal de retour, mais à défaut, peut-être que les personnes avec des dépendances n'écoutent pas sur la liste d'écoute initiale, mais sur ce dont elles dépendent. Ou vous pourriez les faire attendre jusqu'à ce qu'ils aient tous les signaux.

Vous pouvez automatiser la gestion des dépendances en demandant aux auditeurs d'identifier les personnes sur lesquelles ils dépendent. La liste des auditeurs serait ordonnée non pas par ordre d'insertion, mais pour assurer que les objets dépendants suivent leur dépendance. Votre interface d’écoute ressemblerait à ceci:

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

Ou simplement les références, comme suit:

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

"Comment changerions-nous cela pour que l'auditeur B soit à l'écoute de A? Ou même pas au courant, simplement couplé? "

Vous ne voulez pas souvent associer deux " pairs " des objets comme celui-ci. Vous voulez que deux pairs dépendent de quelque chose de commun.

La question la plus profonde est de savoir ce que Listener A ou Listener B fait avec toutes les informations collectées.

Un auditeur fait souvent deux choses: il collecte des données et agit. Souvent, ces deux choses doivent être séparées. Les auditeurs doivent écouter, collectionner et faire un peu plus. Certains autres objets peuvent être activés par un écouteur.

Ce que vous pouvez avoir est juste un auditeur qui a plusieurs actions (A et B). L’auditeur peut alors fournir les décomptes appropriés à A ainsi qu’à B. Il fournit un décompte «a» à A. Il fournit un décompte «a» ou «b» à B.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top