[英]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.