【问题标题】:The best way to have multiple observer lists in observer pattern在观察者模式中拥有多个观察者列表的最佳方式
【发布时间】:2018-10-15 10:11:14
【问题描述】:

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

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

A 是一个发件人/主题,有两个列表,一个用于 Group1,一个用于 Group2。

在主题类中有两个列表是一种好方法吗?

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

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

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

【问题讨论】:

  • 我认为“太宽泛了”。这里有太多假设性问题要先问。比如:这段代码是多线程的吗?请发布代码尝试以及您遇到的问题。
  • @markspace 请看一下
  • 为什么不将Groups 也建模为对象?每个Group 可以有一个List&lt;Sender&gt;(并自动注册为每个Sender 的观察者)。作为回报,Group 可以被观察到,并将其Senders 中的可观察事件转发给它的观察者。这样一来,您就不需要为每个 Sender 创建多个列表,并且拥有更动态的设置来创建不同大小的新 Groups。
  • 是的,我同意 Turing85 的观点,ChatGroup 应该是一个可以封装自己的观察者列表的对象。然而,像这样的代码改进是基于意见的。我建议你试试代码审查网站:codereview.stackexchange.com
  • @desperatecoder 到底哪一部分你不明白?

标签: java design-patterns observers


【解决方案1】:

您当前的设计不一定与观察者模式相矛盾,但它是死板的。截至目前,每个Sender 最多可以分为两组。如果每个发件人最多分为 10 个组怎么办? 100组?为了保持这种设计的灵活性,我建议将Groups 也建模为对象。这个想法是每个Group 同时是一个Observable 和一个Observer。每个Group 都有一个List&lt;Sender&gt; 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 继承。
  • AbstractObserverImpl 也不是必须的abstract。对我来说,允许实例化这个类是没有意义的,因为它缺少它的实际功能(触发Events 的部分)。
  • 我选择创建一个空的Event 接口。这也是任意的。是否将Objects 用作事件、枚举、接口、类或不同的方法完全取决于您。正如我所说:这只是一个粗略的草图。
  • 草图不是null-安全的。有很多可能导致NullPointerExceptions。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-20
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多