观察者模式定义了对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖者都会收到通知并且自动更新。
生活中很多地方用到这种模式,比如说天气预报订阅系统,报纸订阅系统等。
下面一个实例模拟以下发布—-订阅过程
/**
* 观察者
* @author wangzl
*
*/
public class Coder implements Observer {
public String name;
public Coder(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("你好," + name + ",DevteachFrontier更新了,内容 :" + arg);
}
@Override
public String toString() {
return "Coder [name=" + name + "]";
}
}
/**
* 被观察者,当他有更新时,所有的coder都会接到相应的通知
* @author wangzl
*
*/
public class DevteachFrontier extends Observable{
public void postNewContent(String content){
//标识状态或者内容发生改变
setChanged();
//通知所有观察者
notifyObservers(content);
}
}
public class Demo {
public static void main(String[] args) {
// 被观察者角色
DevteachFrontier devteachFrontier = new DevteachFrontier();
// 观察者角色
Coder mrwang = new Coder("王先生");
Coder mrli = new Coder("李先生");
Coder mrzhou = new Coder("周先生");
//将观察者注册到可观察对象的观察者列表中
devteachFrontier.addObserver(mrwang);
devteachFrontier.addObserver(mrli);
devteachFrontier.addObserver(mrzhou);
//发布消息
devteachFrontier.postNewContent("新的周刊发布了,请查看");
}
}
输出结果:
Java 为我们提供了 Observer 接口和 Observable 类,下面我们来介绍一下如何使用。
如何把对象变成观察者 ?
实现观察者接口,然后调用 Observable 对象的 addObserver() 方法。不在想当观察者对象的时候,调用 deleteObserver() 方法就可以了。
可观察者如何送出通知 ?
首先,需要继承 java.util.Observable 类产生可观察者类,然后需要两个步骤。
先调用 setChanged() 方法,标记状态已经改变的事实。
然后调用两种 notifyObservers() 方法中的一个 : notifyObservers() 或者notifyObservers(Object arg)
观察者如何接受通知?
观察者实现了更新的方法,但是方法的签名不太一样 : update(Observable o, Object arg)。 这个时候就可以实现两种不同的效果。如果我们将 Object 属性不指定,也就是只传递 Observable 对象的值,这个时候就是默认不推送给观察者任何信息,不过观察者可以通过被观察者提供的 get 方法主动获取消息(这里也暗示了一个信息,就是我们的观察者内部需要获得被观察者的引用)。如果这里我们指定了 Object 的对象,那么被观察者会将信息推送给观察者。
注意,以上我们提到的 update() 方法中的 Object 参数和被观察者中notifyObservers(Object o) 中的 Object 是对应的。
针对本实例:
这里Observer是抽象的观察者角色,Coder扮演的是具体的观察者角色;Obserable对应的是抽象的主题角色,DevteachFrontier则是具体的主题角色。Coder是具体的观察者角色,它订阅了DevteachFrontier这个具体的被观察者对象,当DevteachFrontier有更新时,会遍历所有 的Coder(观察者),然后给这些观察者发布一个更新消息,即调用Coder中的update方法,这样就达到了一对多的通知功能,在这个过程中,通知系统都是依赖Observer和Obserable这些抽象类,因此对于Coder和DevteachFrontier完全没有耦合,保证了订阅的灵活性,可扩展性。