菜鸟自学的设计模式---即用最简单的方法描述,简单易懂。
总结了书中的内容
观察者是让被观察者的属性发生改变时,相对的观察者会收到通知所有相关属性成员都会发生改变,观察者模式增强了复用率和扩展度。
被观察者
用了jdk自带的被观察者类(Observable),把自己写的被观察者继承Observable即可成为被观察者,先贴出源码
package java.util;
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
可以在notifyObservers方法中看出changed属性成员是一个用来标记是否发送通知的通道,Vector<Observer> obs 是一个用来存放观察者的集合
public void notifyObservers(Object arg) {
//用来接收观察者的数组(用数组可能更方便设计把)
Object[] arrLocal;
synchronized (this) {
//如果通道未打开则不将集合中的观察者放入数组
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
//通过循环调用update接口来向观察者发送通知
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
在父类Observable中各种方法
构造方法用来实例化Vector集合
public Observable() {
obs = new Vector<>();
}
绑定观察者的方法
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
删除观察者的方法
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
通知观察者的方法
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
清除所有观察者的方法
public synchronized void deleteObservers() {
obs.removeAllElements();
}
打开通知通道的方法和关闭通知通道的方法
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
新建一个被观察者的类继承jdk自带的被观察者类Observable(java.util.Observable)同时加入成员变量a和b,编写调用父类通知观察者(notifyObservers)的方法mechanged(),和一个修改值的方法同时调用mechanged(),这样在修改类的属性时将会通知所有的观察者修改对应值
package com.domain;
import java.util.Observable;
/**
* 这是一个被观察者的类,能够在值修改时通知观察者
*/
public class ZT extends Observable {
private int a;
private int b;
public void setA(int a) {
this.a = a;
}
public void setB(int b) {
this.b = b;
}
public void mechanged(){
/**打开通道*/
setChanged();
/**发送通知*/
notifyObservers();
}
/**
* 通过调用此方法改变值,同时发送通知
*/
public void setmechanged(int a, int b){
this.a=a;
this.b=b;
//update();
mechanged();
}
public int getA() {
return a;
}
public int getB() {
return b;
}
}
观察者
jdk同时也为用户提供了观察者的接口Observer,接口中有一个update方法。在被观察者Observable中可以看到通知观察者的方法中有一个循环调用该接口方法的代码
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
即调用实现该方法就会被被通知者调用
所以在观察中类中实现该接口
package com.domain;
import java.util.Observable;
import java.util.Observer;
/**
* 这是一个观察者的类,能够在被观察者属性值发生改变时,获得被观察者的通知
*/
public class GCZA implements Observer {
public int a;
public int b;
public Observable Observable;
public GCZA(Observable Observable){
/**通过构造器绑定被观察者*/
this.Observable=Observable;
Observable.addObserver(this);
}
@Override
public void update(Observable o , Object arg) {
/**从被观察者处获取字段属性*/
ZT zt=(ZT)o;
this.a=zt.getA();
this.b=zt.getB();
dis();
}
/**打印该通知属性的方法*/
public void dis(){
System.out.println("a"+":"+a);
System.out.println("b"+":"+b);
System.out.println("a+b="+(a+b));
}
}
在Observable的通知方法中((Observer)arrLocal[i]).update(this, arg);传入了this所以调用该参数o既可以获取被通知者的对象,然后可以通过对象获取成员属性同时这样就接收到了通知,如果需要多个观察者那么同时实现接口即可
测试
package com.test;
import com.domain.GCZA;
import com.domain.ZT;
import java.util.Observable;
import java.util.Observer;
public class Test extends Observable {
public static void main(String[] args) {
//创建被观察者对象
ZT observable=new ZT();
//创建观察者对象同时绑定被观察者
new GCZA(observable);
//修改属性同时发送通知
observable.setmechanged(1,2);
}
}
结果
a:1
b:2
a+b=3