观察者模式的角色组成
1:抽象主题(Subject)角色:
主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色;
抽象主题角色,有时又叫做抽象被观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。
2:抽象观察者(Observer)角色:
为所有的具体观察者定义一个接口,在得到通知时更新自己;
抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。
3:具体主题(ConcreteSubject)角色:
保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;
具体主题角色,通常用一个具体子类实现。
4:具体观察者(ConcreteObserver)角色:
保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。
具体观察者角色,通常用一个具体子类实现。
程序实践
1:Observer
public interface Observer {
public void update(String str);
}
2:ConcreteObserver1
public class ConcreteObserver1 implements Observer{
@Override
public void update(String str) {
System.out.println("手机客户端--->"+str);
}
}
3:ConcreteObserver2
public class ConcreteObserver2 implements Observer{
@Override
public void update(String str) {
System.out.println("PC"+ "客户端--->"+str);
}
}
4:Subject
public interface Subject {
public void addWatcher(Observer watcher);
public void removeWatcher(Observer watcher);
public void notifyWatchers(String str);
}
5:ConcreteSubject
import java.util.ArrayList;
import java.util.List;
public class ConcreteSubject implements Subject{
// 存放观察者
private List<Observer> list = new ArrayList<Observer>();
@Override
public void addWatcher(Observer watcher) {
list.add(watcher);
}
@Override
public void removeWatcher(Observer watcher) {
list.remove(watcher);
}
@Override
public void notifyWatchers(String str) {
// 自动调用实际上是主题进行调用的
for (Observer watcher : list)
{
watcher.update(str);
}
}
}
6:Test
import java.io.IOException;
import java.util.Map;
public class Test {
public static void main(String[] args) throws NullPointerException, IOException {
Subject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver1();
Observer observer2 = new ConcreteObserver2();
subject.addWatcher(observer1);
subject.addWatcher(observer2);
Map<String, Object> map = WeatherUtil.getTodayWeather("101010100");
subject.notifyWatchers(map.get("city") + ":" + map.get("temp")+ "度(发布时间:" + map.get("time")+")");
}
}
运行结果
手机客户端--->北京:10度(发布时间:10:25)
PC客户端--->北京:10度(发布时间:10:25)
观察者模式的应用场景
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
观察者模式的优点:
1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。
2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
观察者模式的缺陷
1、 松偶合导致代码关系不明显,有时可能难以理解。
2、 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。(毕竟只是简单的遍历)