我正在尝试理解观察者模式,这是我在网上挑选的一个简单代码:
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");
}
}
我几乎得到了这个想法,但有一件事困扰我:Observer有一个setSubject()
方法,他自己(观察者)也注册了主题并设置了主题,这在我看来有点有点不对劲
我可以更改界面并删除setSubject()
方法,但我的问题是,我是否真的需要在注册后设置主题,从观察者模式的角度来看?
答案 0 :(得分:2)
你是对的,这个方法增加了不必要的依赖性,因为这一行:
String msg = (String) topic.getUpdate(this);
可以删除这两种方法(setSubject
和getUpdate
),并且可以msg
直接检索update()
,如下所示:
@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);
}
答案 1 :(得分:1)
问题是,你可以将它与接口分离,这样你就可以构建一个更通用的观察者...然后你的观察对象只需要实现那个观察接口你的观察者准备好了。
答案 2 :(得分:1)
让我们看一下1995年UML中由GoF定义的观察者模式:
ConcreteObserver
与subject
有ConcreteSubject
的链接 - 该模式未指定您如何设置它;它可以在构造函数中注入,也可以使用setSubject()
方法注入。
在Subject
方面,您的代码有register
和unregister
,类似于Attach
和Detach
,以及您的notifyObservers
也适合这种模式。
从Observer模式的角度来看,我是否还需要在注册后设置主题?
根据该模式的GoF版本,ConcreteObserver
必须知道主题才能更新自己。所以,你需要设置一个主题。
模式的变体(Java的Observer
/ Observable
)其中Update()
方法传递包含状态相关信息的对象,以便ConcreteObserver
可以更新其状态,而无需与ConcreteSubject
通信。从理论上讲,您不需要存储指向主题的链接。
模式的目标不是消除所有依赖关系。在软件开发中,有一种趋势是想要添加新的观察者(想想有多少版本的GUI用于Microsoft Word)。主题是不倾向于代码更改的类。软件设计中的一条规则是创建对代码中不太可能发生更改的类的依赖。观察者模式表示ConcreteObservers
往往会发生变化(随着时间的推移有新版本),因此我们不希望也必须更改ConcreteSubjects
。
如果更改主题代码,则该模式无效。例如,让我们拍摄一个代表手机电池剩余电量的主题,其值介于0到10之间。一些观察者使用图形或颜色显示该信息;也许当值低于2时,观察者显示红色图像。现在,如果开发人员决定最好显示从0到100的值,因为它有更多的分辨率来知道电池持续多长时间,你将不得不改变所有观察者的代码(它们取决于主题)。