Лучший способ иметь несколько списков наблюдателей в схеме наблюдателей - PullRequest
0 голосов
/ 05 мая 2018

Я использую шаблон наблюдателя для написания простой программы группового чата.

Группа 1: А, В и С Группа 2: А и С

A - отправитель / субъект с двумя списками, один для группы 1 и один для группы 2.

Является ли наличие двух списков в предметном классе хорошим способом сделать это?

Является ли это нарушением функции шаблона наблюдателя?

Отправитель может иметь две группы наблюдателей.

public class Sender {

    private List<Receiver> group1 = new ArrayList<Receiver>();
    private List<Receiver> group2 = new ArrayList<Receiver>();
    private String msg;
    private String name;

    public Sender(String name) {
        this.name = name;
    }

    public void sendMsg(int group, String msg, JTextArea display) {
        this.msg = msg;
        String output = name + ": " + msg;
        display.append(output + "\n\r");
        if(group == 1) {
            notifyAllObservers(group1);
        } else {
            notifyAllObservers(group2);
        }

    }

    public void register(int group, Receiver receiver) {
        if(group == 1) {
            group1.add(receiver);
        } else {
            group2.add(receiver);
        }

    }

    public void notifyAllObservers(List<Receiver> group) {
        for (Receiver receiver : group) {
            receiver.update(msg);
        }
    }

    public String toString() {
        return name;
    }

}

public class Receiver {

    public Sender sender;
    private JTextArea display;
    public Receiver(int group, Sender sender, JTextArea display) {
        this.sender = sender;
        this.display = display;
        this.sender.register(group, this);
    }

    public void update(String msg) {
        display.append(sender.toString() + ": " + msg + "\n\r");
    }
}

1 Ответ

0 голосов
/ 05 мая 2018

Ваш текущий дизайн не обязательно противоречит шаблону Observer, но он жесткий. На данный момент каждый Sender может состоять из двух групп. Что если каждый отправитель должен быть в 10 группах? 100 групп? Чтобы сохранить этот дизайн гибким, я предлагаю модель Group s как объекты, а также. Идея состоит в том, что каждый Group является Observable и Observer одновременно. Каждый Group имеет List<Sender> senders, для которого он автоматически регистрируется как Observer. Если Group получает некоторое значение Event от одного из Observable s, на которые он зарегистрирован, оно передает это событие своему Observers. Следующий код представляет собой набросок моего предложения.

public interface Observer {
  public void receiveEvent(Observable source, Event event);
}

public interface Observable {
  public void addObserver(Observer observer);
  public void removeObserver(Observer observer);
  public Collection<Observer> getObservers();

  default public void notifyAllObservers(Event event) {
    for (Observer observer : this.getObservers()) {
      observer.receiveEvent(this, event);
    }
  }
}

public interface Event { }

public abstract class AbstractObservableImpl implements Observable {
  private Set<Observer> observers = new HashSet<>();

  @Override
  public final void addObserver(final Observer observer) {
      this.observers.add(observer);
  }

  @Override
  public final void removeObserver(final Observer observer) {
    this.observers.remove(observer);
  }

  @Override
  public final Collection<Observer> getObservers() {
    return Collections.unmodifiableCollection(this.observers);
  }
}

public class Sender extends AbstractObservableImpl { }

public class Group extends AbstractObservableImpl implements Observer {
  private List<Sender> senders = new ArrayList<>();

  @Override
  public final void receiveEvent(final Observable source, final Event event) {
    for (Observer observer : this.getObservers()) {
      observer.receiveEvent(this, event);
    }
  }

  public final void addSender(Sender sender) {
    if (this.senders.contains(sender) == false) {
      this.senders.add(sender);
    }
    this.senders.get(this.senders.indexOf(sender)).addObserver(this);
  }

  public final void removeSender(Sender sender) {
    final int index = this.senders.indexOf(sender));
    if (index >= 0)  {
      this.senders.get(index).removeObserver(this);
    }
    this.senders.remove(sender);
  }
}

Некоторые замечания по дизайну:

  • abstract class AbstractObserverImpl не является обязательным. Мне просто было лень повторять код, и поскольку Sender и Group не наследуют от чего-либо еще, я позволил им наследовать от AbstractObserverImpl.
  • Также не обязательно, чтобы AbstractObserverImpl было abstract. Для меня не было бы никакого смысла разрешать создание экземпляров этого класса, поскольку ему не хватает его действительной функциональности (часть, запускающая Event s).
  • Я решил создать пустой интерфейс Event. Это arbirtrary aswell. Используете ли вы Object s как события, или перечисления, или интерфейс, или класс, или другой подход, полностью зависит от вас. Как я уже сказал: это всего лишь грубый набросок.
  • Эскиз не null -безопасен. Есть довольно много причин, чтобы вызвать NullPointerException с.
...