Java观察者模式或发布者-订阅者模式的变体

时间:2019-06-28 00:46:25

标签: java design-patterns publish-subscribe observer-pattern

以下2个变体中的实际观察者模式是什么?

  1. 在第一个中,观察员负责 订阅。
  2. 但是在第二种情况下,发布服务器采用了 将特定观察者添加到订户列表的责任。

因为,网络上有一些实现,将它们都当作java中的观察者模式。

    1。
    // Observer is taking the responsibility of subscribing 
    // Observer.java
    @Override
    public void subscribe(MessagePublisher publisher) {
        publisher.getObservers().add(this);
    }

2。

    // Publisher is taking the observer to subscribe
    // Publisher.java
     @Override
     public void addObserver(Observer observer) {
       observers.add(observer);
     }

4 个答案:

答案 0 :(得分:1)

我怀疑他们俩都是。他们俩都必须实现Observer接口。

答案 1 :(得分:1)

第二个示例正在实现所谓的观察者模式。您(观察者)想要通知对象X(可观察对象)中发生的某些事件,对吗?比您会告诉观察者通知您。换句话说,您开始听它,这就是为什么它也被称为监听器。 Observable并不了解所有订户。他只需要将它们添加到容器或集合中即可。观察者知道所有观察者都实现的接口IObserver,因此知道要调用哪种方法(回调)。

第一个例子没有道理。可观察者对观察者调用一种方法使他订阅?该设计流程一定很奇怪。

假设您有一个FileWriter类,它公开了一个事件FileWriter.Completed。您还有另一个用于管理所有文件的类FileHandlerFileHandler调用FileWriter.write(filePath, data)。每次操作后,FileHandler要向用户显示一条消息。因此,“ FileWriter is used by the FileHandler , but without knowing who's calling the write method. The FileHandler , one of the many consumers of FileWriter.write(string,string), knows that FileWriter实现了一个称为{{1} }。这就是为什么他可以确定可观察对象具有方法IWriteToFileCompletedEvent的原因。您想让FileWriter.subscribeToWriteToFileCompleted(IObserver eventListener)在其订阅之前 知道他的活动的所有消费者吗?想一想。这将是一些奇怪的API,例如:FileWriter,用于向FileWriter.write(filepath, data, this)提供对侦听器的引用。然后FileWriter接受侦听器引用并调用FileWriter。现在listener.subscribe(this)(侦听器)对FileHandler有了无用的引用(无用,因为他之前知道FileWriter,因为他在上面调用了FileWriter),所以侦听器接受他已经必须调用FileWriter.write的{​​{1}}参考。输入此字时中风。说真的,这是一些疯狂的意大利面条。

这就是真实实现在“现实生活”中的样子

FileWriter

类将像这样交互

observable.getObservers().add(this)

类型完全不同的多个对象(// The interface for the publisher or observable of a special event interface IWriteToFileCompletedEvent { void subscribeToWriteToFileCompleted(IWriteToFileCompletedListener observer); void unsubscribeToWriteToFileCompleted(IWriteToFileCompletedListener observer); } // The interface for the observer of a special event interface IWriteToFileCompletedListener { void notify(string filePathOfCompletedFile); } // The observable that exposes a special event class FileWriter implements IWriteToFileCompletedEvent { private List<IWriteToFileCompletedListener> writeToFileCompletedListeners = new ArrayList<>(); public void subscribeToWriteToFileCompleted(IWriteToFileCompletedListener observer) { this.writeToFileCompletedListeners.add(observer); } public void unsubscribeToWriteToFileCompleted(IWriteToFileCompletedListener observer) { this.writeToFileCompletedListeners.remove(observer); } public void writeToFile(string filePath, string data) { // Write data to file // Once done notify all listeners of the write completed event for (IWriteToFileCompletedListener observer : this.writeToFileCompletedListeners) { observer.notify(filePath); } } } // The observer of a special event class ContactsHandler implements IWriteToFileCompletedListener { private FileWriter fileWriter = new FileWriter(); public void saveUserContactToFile(string filePath, string userInput) { this.fileWriter.subscribeToWriteToFileCompleted(this); this.fileWriter.writeToFile(filePath, userInput); } // Implementation of interface IWriteToFileCompletedListener public void notify(string filePath) { this.fileWriter.unsubscribeToWriteToFileCompleted(this); this.messageDialog.show("The new contact was successfully saved to " + filePath); } } // Another observer of a special event class SettingsHandler implements IWriteToFileCompletedListener { private FileWriter fileWriter = new FileWriter(); public void saveUserSettingsToFile(string filePath, string userSettings) { this.fileWriter.subscribeToWriteToFileCompleted(this); this.fileWriter.writeToFile(filePath, userSettings); } // Implementation of interface IWriteToFileCompletedListener public void notify(string filePath) { this.fileWriter.unsubscribeToWriteToFileCompleted(this); this.messageDialog.show("The new settings were successfully saved to " + filePath); } } public void main(strng[] args { SettingsHandler settingsHandler = new SettingsHandler(); ContactsHandler contactsHandler = new ContactsHandler(); // Imaging this method receives user input fromo the UI: string newContact = textBox.gettext(); this.contactsHandler.saveUserContactToFile("C:\Contacts.txt", newContact); // While waiting for the message to show the user adjusted some settings and clicked 'save' string changedSettings = getChangedSettings(); this.settingsHandler.saveUserSettingsToFile("C:\UserSettings.txt", changedSettings); // After a while the user sees the messages send from the event listeners. } )预订了同一事件。一切都干净。使用他要观察的对象的objtec进行订阅。可以观察到的类(可观察的)仅通知所有订阅者。而已。

总结一下:您的解决方案1 ​​根本不方便(尽管您可以使它工作)并产生难看的代码。

解决方案2 实际上遵循描述如何实现事件的模式。该实现已得到证明并得到了很好的确立,因为它实现了引入事件并生成清晰可读的代码的目的。

答案 2 :(得分:1)

观察者是应该注册自己还是让另一个实体来处理此责任,这是应用观察者模式时的实现决策,而不是模式本身的结构方面。因此,遇到这两种变化并不奇怪。

在GoF书和其他地方记录的模式结构中,Subject有一个Attach(和Detach)方法作为其接口的一部分。这意味着任何引用主题的实体都可以调用Attach并执行此注册。

答案 3 :(得分:0)

两者都是Observer模式的有效实现,但是,除非明确需要公开观察者列表,否则第二种方法是可取的。