[英]Observer pattern - does the observer needs to know the Subject ?
我試圖了解觀察者模式,這是我在網上選擇的一個簡單代碼:
import java.util.ArrayList;
import java.util.List;
/**
* The observer pattern is a software design pattern in which an object,
* called the subject, maintains a list of its dependents, called observers, and
* notifies them automatically of any state changes, usually by calling one of their methods
* @author X220
*
*/
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);
}
interface Observer
{
// method to update the observer, used by subject
public void update();
// attach with subject to observe
public void setSubject(Subject sub);
}
/**
* Holds a list of the observers
* @author X220
*
*/
class MySubject implements Subject
{
private List<Observer> observers;
private String message;
private boolean changed;
private final Object MUTEX = new Object();
public MySubject()
{
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();
}
}
class MyObserver implements Observer
{
private String name;
private Subject topic;
public MyObserver(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;
}
}
public class RunCode1
{
public static void main1(String[] args) {
// create subject
MySubject topic = new MySubject();
// create observers
Observer obj1 = new MyObserver("Obj1");
Observer obj2 = new MyObserver("Obj2");
Observer obj3 = new MyObserver("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");
}
}
我幾乎了解了這個主意,但是有一件事情困擾着我:觀察者有一個setSubject()
方法,他本人(觀察者)也注冊了subject並設置了Subject,在我看來這有點不對勁。
我可以更改接口並刪除setSubject()
方法,但是我的問題是從Observer模式的角度來看,我真的還需要在注冊后設置一個主題嗎?
沒錯,由於此行,此方法添加了不必要的依賴性:
String msg = (String) topic.getUpdate(this);
可以刪除這兩個方法( setSubject
和getUpdate
),並且可以從update()
直接檢索msg
,如下所示:
@Override
public void update(String msg) {
if (msg == null) {
System.out.println(name + ":: No new message");
} else
System.out.println(name + ":: Consuming message::" + msg);
}
隨着notifyObservers
的更新:
for (Observer obj : observersLocal)
{
obj.update(this.message);
}
好吧,觀察者必須知道有關他的主題的細節,否則他將無法觀察它,對嗎? 與現實生活相匹配:您還必須了解正在觀察的對象的那些細節,以便在何時需要采取特定措施時知道對不對?
關鍵是, 您可以將其與interfaces分離 ,因此您可以構建一個更通用的觀察者...然后,您所觀察的對象只需要實現該觀察接口,觀察者就可以使用了。
讓我們看看1995年UML中GoF定義的Observer模式:
ConcreteObserver
有一個鏈接subject
的ConcreteSubject
-模式沒有指定如何設置它; 可以將其注入構造函數中,也可以使用setSubject()
方法注入。
在Subject
方面,您的代碼具有register
和unregister
,類似於Attach
和Detach
,並且notifyObservers
適合該模式。
從觀察者模式的角度來看,我真的還需要在注冊后設置主題嗎?
根據此模式的GoF版本, ConcreteObserver
必須以某種方式知道主題才能進行自我更新。 因此,您需要設置一個主題。
模式的一種變體(Java的Observer
/ Observable
),其中Update()
方法傳遞一個對象,該對象包含與狀態有關的信息,以便ConcreteObserver
可以更新其狀態而不必與ConcreteSubject
進行通信。 從理論上講,您然后不需要存儲指向該主題的鏈接。
模式的目標不是消除所有依賴性。 在軟件開發中,有一種趨勢是希望添加新的觀察者(考慮Microsoft Word的GUI版本有多少)。 主題是傾向於不更改代碼的類。 軟件設計中的一條規則是在不大可能更改其代碼的類上創建依賴項 。 觀察者模式是說ConcreteObservers
傾向於改變(隨着時間的推移有新版本),因此我們不想也必須改變ConcreteSubjects
。
如果您更改主題的代碼,該模式將無濟於事。 例如,讓我們以代表手機電池剩余電量的主題為例,其值的范圍是0到10。 也許當值小於2時,觀察者會顯示紅色圖像。 現在,如果開發人員決定最好顯示0到100的值,因為它具有更多的分辨率來知道電池可持續使用多長時間,則您必須更改所有觀察者的代碼(它們取決於主題)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.