Правильная связь для нескольких слушателей, которым необходим доступ к данным общего состояния

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

  •  07-07-2019
  •  | 
  •  

Вопрос

Работа с традиционной моделью обратного вызова слушателя. У меня есть несколько слушателей, которые собирают разные вещи. Собранные вещи каждого слушателя находятся внутри слушателя во внутренних структурах.

Проблема в том, что я хочу, чтобы некоторые слушатели знали о некоторых «вещах». в других слушателей.

Я применяю порядок регистрации слушателя, поэтому, если я сознательно регистрирую события в каком-то порядке, более поздний слушатель может быть уверен, что ранее прослушиватель обновил свои данные и каким-то образом получил к ним доступ, чтобы делать больше вещей.

Моя первая попытка сделать так, чтобы каждый слушатель сохранял ссылку на слушателей, от которых он зависит. Поэтому я регистрирую прослушиватели в порядке тех, у кого нет зависимостей, и тех, у кого были предварительно зарегистрированные зависимости, а затем устанавливаю ссылки между слушателями различными способами.

Я начинаю понимать, как это плохо, и мне было интересно, был ли как-то этот путь раньше. Что может быть более подходящим шаблоном, когда одному из слушателей нужен доступ к материалу другого?

Вот несколько псевдокодов для иллюстрации:

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);
   }
 }
}
Это было полезно?

Решение

Почему бы не иметь центральный объект, который будет отслеживать, сколько раз метод 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

Другие советы

Вы описали много связей здесь. Лучше всего было бы устранить всю эту зависимость от обратного канала, но в противном случае, возможно, у вас могли бы быть те, с зависимостями, которые слушали бы не исходный список слушателей, а то, от чего они зависят. Или вы можете попросить их подождать, пока они не получат все сигналы.

Вы можете автоматизировать управление зависимостями, попросив слушателей определить, от кого они зависят. Список слушателей будет упорядочен не по порядку вставки, а для обеспечения того, чтобы зависимые объекты следовали за их зависимостями. Ваш интерфейс слушателя будет выглядеть примерно так:

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

Или просто есть ссылки, например, так:

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

" Как бы мы изменили это так, чтобы слушатель B знал о слушателе A? Или даже не в курсе, просто как-то связаны? & Quot;

Вы не часто хотите соединить два "равных" объекты как это. Вы хотите, чтобы два сверстника зависели от чего-то общего.

Более глубокий вопрос заключается в том, что Слушатель А или Слушатель Б делают со всей информацией, которую они собирают?

Слушатель часто делает две вещи: он собирает данные и предпринимает действия. Часто эти две вещи должны быть разделены. Слушатели должны слушать, собирать и делать немного больше. Слушатель может активировать некоторые другие объекты.

У вас может быть только один слушатель, у которого есть несколько действий (A и B). Затем слушатель может предоставить соответствующие счетчики для A, а также B. Он предоставляет счетчик «a» для A. Он предоставляет счетчик «a» или «b» для B.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top