在观察者模式中拥有多个观察者列表的最佳方式

The best way to have multiple observer lists in observer pattern

我正在使用观察者模式编写一个简单的群聊程序。

第 1 组:A、B 和 C 第 2 组:A 和 C

A 是一个 sender/subject,有两个列表,一个用于 Group1,一个用于 Group2。

在主题 class 中有两个列表是执行此操作的好方法吗?

这是否违反了观察者模式的特性?

一个发送者可以有两组观察者。

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");
    }
}

你目前的设计不一定与观察者模式相矛盾,但它是死板的。截至目前,每个 Sender 最多可以分为两组。如果每个发件人应该在最多 10 个组中怎么办? 100组?为了保持这种设计的灵活性,我建议也将 Group 建模为对象。这个想法是每个 Group 同时是一个 Observable 和一个 Observer。每个 Group 都有一个 List<Sender> senders,它会自动注册为 Observer。如果 Group 从它注册的 Observable 之一收到一些 Event,它将把这个事件转发给它的 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 不是必需的。我只是懒得重复代码,因为 SenderGroup 不继承任何其他东西,我让它们继承自 AbstractObserverImpl.
  • AbstractObserverImplabstract 也不是必须的。对我来说,允许实例化这个 class 是没有意义的,因为它缺少它的实际功能(触发 Event 的部分)。
  • 我选择创建一个空的 Event 界面。这也是武断的。是否将 Object 用作事件、枚举、接口、class 或其他方法,完全取决于您。正如我所说:这只是一个粗略的草图。
  • 草图 null 不安全。有相当多的可能性导致 NullPointerExceptions.