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

时间:2018-05-04 21:13:01

标签: java design-patterns observers

我使用观察者模式编写一个简单的群聊项目。

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

1 个答案:

答案 0 :(得分:1)

您当前的设计不一定与观察者模式相矛盾,但它是僵化的。截至目前,每个Sender最多可以包含两个组。如果每个发件人最多可以包含10个组,该怎么办? 100组?为了保持这种设计的灵活性,我建议将Group s建模为对象。我们的想法是每个Group同时是ObservableObserver。每个Group都有一个List<Sender> senders,它会自动注册为Observer。如果Group从其注册的Event之一收到一些Observable,则会将此事件转发给其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也不是必需的。对我来说,允许实例化这个类是没有意义的,因为它缺少它的实际功能(触发Event s的部分)。
  • 我选择创建一个空Event接口。这也是arbirtrary。无论您使用Object作为事件,还是枚举,界面,类或不同的方法都完全取决于您。正如我所说:这只是一个粗略的草图。
  • 草图不是null - 安全。有很多可能导致NullPointerException s。
相关问题