观察者模式(Observer)就是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。
通过一个一个抽象的主题Subject保存了多个信息处理列表,可以添加多个观察者,实现即时的通知观察者最新动态然后分别派生子类对象对具体的消息和状态做出处理。
观察者模式的组成
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
抽象观察者Watcher.java
public interface Watcher
{
public void update(String str);
}
抽象主题Watched.java
public interface Watched
{
public void addWatcher(Watcher watcher);
public void removeWatcher(Watcher watcher);
public void notifyWatchers(String str);
}
观察者实现ConcreteWatcher.java
public class ConcreteWatcher implements Watcher
{
@Override
public void update(String str)
{
System.out.println(str);
}
}
被观察主题实现ConcreteWatched.java
import java.util.ArrayList;
import java.util.List;
public class ConcreteWatched implements Watched
{
// 存放观察者
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWatcher(Watcher watcher)
{
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher)
{
list.remove(watcher);
}
@Override
public void notifyWatchers(String str)
{
// 自动调用实际上是主题进行调用的
for (Watcher watcher : list)
{
watcher.update(str);
}
}
}
测试类Test.java
public class Test
{
public static void main(String[] args)
{
Watched girl = new ConcreteWatched();
Watcher watcher1 = new ConcreteWatcher();
Watcher watcher2 = new ConcreteWatcher();
Watcher watcher3 = new ConcreteWatcher();
girl.addWatcher(watcher1);
girl.addWatcher(watcher2);
girl.addWatcher(watcher3);
girl.notifyWatchers("开心");
}
}
观察者模式分为推和拉2种
“拉”的方式是指,各个Observer维护各自所关心的Subject列表,自行决定在合适的时间去Subject获取相应的更新数据。
“推”的好处包括:
1、高效。如果没有更新发生,不会有任何更新消息推送的动作,即每次消息推送都发生在确确实实的更新事件之后,都是有意义的。
2、实时。事件发生后的第一时间即可触发通知操作。
3、可以由Subject确立通知的时间,可以避开一些繁忙时间。
4、可以表达出不同事件发生的先后顺序。
“拉”的好处包括:
1、如果观察者众多,Subject来维护订阅者的列表,可能困难,或者臃肿,把订阅关系解脱到Observer去完成。
2、Observer可以不理会它不关心的变更事件,只需要去获取自己感兴趣的事件即可。
3、Observer可以自行决定获取更新事件的时间。
4、拉的形式可以让Subject更好地控制各个Observer每次查询更新的访问权限。
jdk中的观察者模式使用
public class Monitored extends Observable {
public void sendMessage(String str){
this.setChanged();
this.notifyObservers(str);
}
}
/**
* 观察者1
*/
public class Watcher1 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("Watcher1 receive:" + (String)arg);
}
}
/**
* 观察者2
*/
public class Watcher2 implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("Watcher2 receive:" + (String)arg);
}
}
public static void main(String[] args){
//创建被观察对象
Monitored monitored = new Monitored();
//创建两个观察者
Watcher1 watcher1 = new Watcher1();
Watcher2 watcher2 = new Watcher2();
//添加观察者
monitored.addObserver(watcher1);
monitored.addObserver(watcher2);
//被观察者发送消息给观察者
monitored.sendMessage("这是一条消息");
}
使用场景
zookeeper使用了观察者模式。