一:观察者模式
定义一对多(1:n)的对象关系,如果1
发生变化,那么n
都会收到通知,这叫观察者模式。当然,我觉得叫”出版者——订阅者”模式更加容易理解。就像你在报社订了报纸,只要报社有新报纸出版,送报员就会给你家送一份,如果不想要,还可以退定。
二:来个栗子
举一个Head First
书上的栗子:
首先这是一个气象局的显示系统,WeatherData
是数据的来源,Subject
是一个公共基础主题,Observer
是观察者的父类。WeatherData
的数据如果更新,我希望forecastObserver
这个面板上的数据也更新,为了使结构简单,我没有添加xObserver
和yObserver
等其他的Observer
,但是并不代表它们不存在(实际上是可以任意扩展的)。
当然,在系统中,WeatherData
也只是数据变化的一部分,如果有两部分或者更多,我们可以继续有OtherData...
,让它继承自Subject
就好了。Subject
中定义的方法addObserver
可以被forecastObserver
显式的调用将自己添加到WeatherData
主题中,这样,WeatherData
更新的数据就会在notifyobserver
中以update
的方式更新到forecastObserver
中。
至于forecastObserver
中的Subject sub
元素,就是作为一个观察者,我最起码应该知道我订阅了谁的出版吧,即使以后去退订,也应该知道找谁(调用谁的方法)。
三:实现如下
Subject.java
public interface Subject {
public void addobserver(Observer ob);
public void delobserver(Observer ob);
public void notifyobserver();
}
Observer.java
public interface Observer {
public void update(int a,int b,int c);
}
WeatherData.java
public class WeatherData implements Subject {
private ArrayList arrayList = new ArrayList();
private int x;
private int y;
private int z;
public void addobserver(Observer ob) {
arrayList.add(ob);
}
public void delobserver(Observer ob) {
int i = arrayList.indexOf(ob);
if(i >= 0) {
arrayList.remove(i);
}
}
public void notifyobserver() {
for (int i = 0; i < arrayList.size(); i++) {
Observer ob = (Observer) arrayList.get(i);
ob.update(x,y,z);
}
}
public void setvalue(int a,int b,int c) {
this.x = a;
this.y = b;
this.z = c;
notifyobserver();
}
}
forecastObserver.java
public class forecastObserver implements Observer {
private Subject myobj;
private int x;
private int y;
public forecastObserver(Subject ob) {
this.myobj = ob; //保存自己的出版者
ob.addobserver(this);
}
public void update(int a, int b, int c) {
this.x = a;
this.y = b;
display();
}
public void display() {
System.out.println("x is " + x + " y is " + y);
}
}
main.java
public class main {
public static void main(String[] args) {
WeatherData wd = new WeatherData(); //定义出版者
forecastObserver fo = new forecastObserver(wd); //订阅者
wd.setvalue(1,2,3); //出版者不断变化新的数据
wd.setvalue(4,5,6);
wd.setvalue(7,8,9);
}
}
结果如下:
四:总结
好处:
- 面向接口编程,组合要比继承好。
- 无论是订阅者增加还是观察者增加都非常容易扩展。
缺点:
- 数据的更新是被动的。会将不需要的数据一并更新过来,比如上面栗子中
forecastObserver
不需要z
数据,但是Subject
还是将数据更新过来了。
五:后续工作
- 将此模式更改为可以主动
拉
数据的。 JDK
内置观察者模式,改天试一试。