acoplamento adequado para vários ouvintes que precisam de dados estado compartilhado acessada

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

  •  07-07-2019
  •  | 
  •  

Pergunta

Trabalho com um modelo de ouvinte callback tradicional. Tenho vários ouvintes que coletam várias coisas. material coletado de cada ouvinte está dentro do ouvinte em estruturas internas.

O problema é que eu quero que alguns dos ouvintes de estar ciente de algumas das "coisas" nos outros ouvintes.

I respeitar a ordem de inscrição ouvinte, então se eu conscientemente registrar eventos em alguma ordem um ouvinte mais tarde pode ter certeza que a anteriormente ouvinte atualizou seu material e de alguma forma acessá-lo a fazer mais coisas.

A minha primeira tentativa neste sentido é ter cada loja ouvinte uma referência para os ouvintes dos quais ele depende. Então eu registrar ouvintes na ordem dos sem dependências para aqueles com dependências anteriores-registrados e defina as referências entre os ouvintes em vários métodos.

Eu estou começando a perceber o quão ruim este se sente e eu queria saber se de alguma forma tem sido por este caminho antes. O que seria um padrão mais apropriado quando uma das necessidades ouvintes a coisas de acesso em outro?

Aqui estão algumas pseudocódigo 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);
   }
 }
}
Foi útil?

Solução

Por que não ter um objeto central que vai manter o controle de quantas vezes o método onEvent foi demitido por todas as classes de ouvintes

 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

Outras dicas

Você descrevendo um monte de acoplamento aqui. Melhor seria eliminar toda essa dependência back-canal, mas não que talvez você poderia ter aqueles com dependências de escuta não está na lista ouvinte inicial, mas em tudo o que eles são dependentes. Ou você pode tê-los esperar até que eles têm todos os sinais.

Você pode automatizar o gerenciamento de dependência por ter os ouvintes identificar quem eles são dependentes. A lista ouvinte seria não ordenados por ordem de inserção, mas para segurar objetos dependentes seguir sua dependência. Sua interface ouvinte seria algo parecido com isto:

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

Ou apenas tem as referências, assim:

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

"Como podemos mudar isso para que Listener B é ouvinte uma consciência? Ou não mesmo ciente, apenas alguma forma acoplados?"

Você muitas vezes não querem casal dois objetos "peer" como este. Você quer que dois pares de depender de algo comum.

A questão mais profunda é o que Listener A ou B Listener ver com toda a informação que recolhemos?

Um ouvinte muitas vezes faz duas coisas: ele coleta dados e leva ação. Muitas vezes, essas duas coisas precisam ser separados. Os ouvintes devem ouvir e coletar e fazer pouco mais. Algum outro objeto (s) pode ser ativado por um ouvinte.

O que você pode ter é apenas um ouvinte que tem várias ações (A e B). O ouvinte pode então fornecer contagens apropriadas para A, bem como B. Ele fornece um 'a' contagem para A. Ele fornece um 'a' contagem ou 'b' para B.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top