觀察者模式是行爲設計模式之一。當您對對象的狀態感興趣並但願在有任何更改時收到通知時,觀察者設計模式很是有用。在觀察者模式中,監視另外一個對象狀態的對象稱爲Observer,正在被監視的對象稱爲Subject。
java
根據GoF,觀察者設計模式的意圖是;設計模式
定義對象之間的一對多依賴關係,以便當一個對象更改狀態時,將自動通知和更新其全部依賴項。框架
Subject包含一個觀察者列表,用於通知其狀態的任何變化,所以它應該提供觀察者能夠註冊和註銷本身的方法。Subject還包含一種方法,用於通知全部觀察者任何更改,而且能夠在通知觀察者時發送更新,或者它能夠提供另外一種方法來獲取更新。ide
Observer應該有一個方法來設置要監視的對象,以及Subject將使用的另外一個方法來通知它們任何更新。
Java提供了內置平臺,用於經過java.util.Observable類和java.util.Observer接口實現Observer模式。可是它沒有被普遍使用,由於實現很是簡單,而且大多數時候咱們不但願最終擴展類只是爲了實現Observer模式,由於java不在類中提供多重繼承。post
Java消息服務(JMS)使用Observer設計模式以及Mediator模式,容許應用程序訂閱數據並將數據發佈到其餘應用程序。測試
模型 - 視圖 - 控制器(MVC)框架也使用Observer模式,其中Model是Subject,而Views是觀察者,能夠註冊以得到對模型的任何更改的通知。this
對於咱們的觀察者模式java程序示例,咱們將實現一個簡單的Subject,觀察者能夠註冊到這個Subject。每當有任何新消息發佈到Subject時,將通知全部寄存器觀察者而且他們可使用該消息。翻譯
根據Subject的要求,這裏是基礎Subject接口,它定義了由任何具體Subject實現的契約方法。設計
package com.journaldev.design.observer; public interface Subject { //methods to register and unregister observers public void register(Observer obj); public void unregister(Observer obj); //method to notify observers of change public void notifyObservers(); //method to get updates from subject public Object getUpdate(Observer obj); }
接下來咱們將爲Observer建立契約,將有一個方法將Subject附加到觀察者,以及Subject要用來通知任何更改的另外一個方法。code
package com.journaldev.design.observer; public interface Observer { //method to update the observer, used by subject public void update(); //attach with subject to observe public void setSubject(Subject sub); }
如今咱們的契約準備好了,讓咱們繼續咱們Subject的具體實施。
package com.journaldev.design.observer; import java.util.ArrayList; import java.util.List; public class MyTopic implements Subject { private List<Observer> observers; private String message; private boolean changed; private final Object MUTEX= new Object(); public MyTopic(){ this.observers=new ArrayList<>(); } @Override public void register(Observer obj) { if(obj == null) throw new NullPointerException("Null Observer"); synchronized (MUTEX) { if(!observers.contains(obj)) observers.add(obj); } } @Override public void unregister(Observer obj) { synchronized (MUTEX) { observers.remove(obj); } } @Override public void notifyObservers() { List<Observer> observersLocal = null; //synchronization is used to make sure any observer registered after message is received is not notified synchronized (MUTEX) { if (!changed) return; observersLocal = new ArrayList<>(this.observers); this.changed=false; } for (Observer obj : observersLocal) { obj.update(); } } @Override public Object getUpdate(Observer obj) { return this.message; } //method to post message to the topic public void postMessage(String msg){ System.out.println("Message Posted to Topic:"+msg); this.message=msg; this.changed=true; notifyObservers(); } }
註冊和取消註冊觀察者的方法實現很是簡單,額外的方法是postMessage(),戶端應用程序將使用它將String消息發佈到主題。請注意布爾變量,以跟蹤主題狀態的變化並用於通知觀察者。此變量是必需的,所以若是沒有更新而且某人調用notifyObservers(),則它不會向觀察者發送錯誤通知。
還要注意在notifyObservers()方法中使用同步,以確保僅將通知發送給在將消息發佈到主題以前註冊的觀察者。
如下是將觀察主題的觀察者的實施。
package com.journaldev.design.observer; public class MyTopicSubscriber implements Observer { private String name; private Subject topic; public MyTopicSubscriber(String nm){ this.name=nm; } @Override public void update() { String msg = (String) topic.getUpdate(this); if(msg == null){ System.out.println(name+":: No new message"); }else System.out.println(name+":: Consuming message::"+msg); } @Override public void setSubject(Subject sub) { this.topic=sub; } }
注意update()方法的實現,它調用Subject getUpdate()方法來獲取要使用的消息。咱們能夠經過將message做爲參數傳遞給update()方法來避免這種調用。
這是一個簡單的測試程序,用於使用咱們的Subject主題實現。
package com.journaldev.design.observer; public class ObserverPatternTest { public static void main(String[] args) { //create subject MyTopic topic = new MyTopic(); //create observers Observer obj1 = new MyTopicSubscriber("Obj1"); Observer obj2 = new MyTopicSubscriber("Obj2"); Observer obj3 = new MyTopicSubscriber("Obj3"); //register observers to the subject topic.register(obj1); topic.register(obj2); topic.register(obj3); //attach observer to subject obj1.setSubject(topic); obj2.setSubject(topic); obj3.setSubject(topic); //check if any update is available obj1.update(); //now send message to subject topic.postMessage("New Message"); } }
當咱們運行上面的程序時,咱們獲得如下輸出。
Obj1:: No new message Message Posted to Topic:New Message Obj1:: Consuming message::New Message Obj2:: Consuming message::New Message Obj3:: Consuming message::New Message
觀察者設計模式也稱爲發佈 - 訂閱模式。其中一些實現是:
在如下任何一種狀況下使用Observer模式
這就是java中的Observer設計模式,我但願你喜歡它。與評論分享您的愛,並與他人分享。
翻譯於:observer-design-pattern-in-java