观察者模式介绍
观察者模式是一种非常有用的设计模式,在软件系统中,当一个对象的行为依赖于另一个对象的状态时,观察者模式就非常有用。如果不适用观察者模式,而实现类似的功能,可能就需要另外启动一个线程不停地监听另一个对象的状态,这样会得不偿失。如果在一个复杂的系统中,可能就需要开启很多的线程来监听对象状态的变化,这样会使系统的性能产生额外的负担。而观察者模式就可以在单线程下使某一对象及时得知所依赖对象状态的变化而做出行为。
观察者模式的经典结构:
其中ISubject是观察对象(被观察者对象),它维持着一个观察者对象列表,可以增加或删除观察者。IObserver是观察者,它依赖于ISubject对象状态的变化而做出行为。当ISubject对象的状态发生变化时,它可以通过inform()方法通知观察者。
观察者模式的主要角色功能如下图:
观察者实例
现在简单实现一个观察者的小例子。
主题接口:
1 public interfaceISubject {2 voidattach(IObserver observer);3 voiddetach(IObserver observer);4 voidinform();5 }
观察者接口:
1 public interfaceIObserver {2 voidupdate(Event event);3 }
事件(对应现实中的点击等事件也可以理解为上文中说到的状态变化):
1 public classEvent {2
3 }
具体的主题实现:
1 public class ConcreteSubject implementsISubject {2 Vector obversers = new Vector();//观察者队列
3 @Override4 public voidattach(IObserver observer) {5 obversers.add(observer);6 }7
8 @Override9 public voiddetach(IObserver observer) {10 obversers.remove(observer);11 }12
13 @Override14 public voidinform() {15 Event event = newEvent();16 for(IObserver obverser:obversers){17 obverser.update(event);18 }19 }20
21 }
具体的观察者:
1 public class ConcreteObserver implementsIObserver {2
3 @Override4 public voidupdate(Event event) {5 System.out.println("ConcreteObserver.update()");6 }7
8 }
测试代码:
public classTest {public static voidmain(String[] args) {
IObserver observer1= newConcreteObserver();
IObserver observer2= newConcreteObserver();
ISubject subject= newConcreteSubject();
subject.attach(observer1);
subject.attach(observer2);
subject.inform();
}
}
可以看出,通过被观察者状态变化而调用某一方法使观察者收到通知而做出反应,通过委托降低了代码的耦合度。
观察者模式十分常用,以致于JDK内部就为开发人员准备了一套观察者模式的实现。在java.util包中,就包括了Obserable类和Observer接口。在Observable中就实现了观察对象的主要功能,如:添加观察者、删除观察者和通知观察者等。Observer是观察者接口,它的update方法会在Obserable类的
以现在比较火热的购房作为观察者模式的一个例子:现在很多购房者关注房价的变化,每当房价发生变动的时候,购房者就会收到通知。这样购房者就是观察者,他们关注着房子的价格。
观察对象房子代码:
1 public class House extendsObservable{2 private floatprice;3
4 public House(floatprice) {5 super();6 this.price =price;7 }8
9 public floatgetPrice() {10 returnprice;11 }12
13 public void setPrice(floatprice) {14 super.setChanged();//设置变化点
15 super.notifyObservers(price);//价格变动
16 this.price =price;17 }18
19 @Override20 publicString toString() {21 //TODO Auto-generated method stub
22 return "房子的价格为:"+this.price;23 }24 }
观察者购房者代码:
1 public class CustomerObserver implementsObserver{2
3 privateString name;4
5 publicCustomerObserver(String name) {6 super();7 this.name =name;8 }9
10 @Override11 public voidupdate(Observable o, Object arg) {12 if (arg instanceofFloat) {13 System.out.println(this.name+"观察到房子价格变动为:"+arg);14 }15 }16 }
测试代码:
1 public classTest1 {2 public static voidmain(String[] args) {3 House h = new House(1000000) ;4 CustomerObserver hpo1 = new CustomerObserver("购房者A") ;5 CustomerObserver hpo2 = new CustomerObserver("购房者B") ;6 CustomerObserver hpo3 = new CustomerObserver("购房者C") ;7 h.addObserver(hpo1) ;8 h.addObserver(hpo2) ;9 h.addObserver(hpo3) ;10 System.out.println(h) ; //输出房子价格
11 h.setPrice(666666) ; //修改房子价格
12 System.out.println(h) ; //输出房子价格
13 }14 }
输出结果为:
1 房子价格为:1000000.0
2 购房者C观察到价格更改为:666666.0
3 购房者B观察到价格更改为:666666.0
4 购房者A观察到价格更改为:666666.0
5 房子价格为:666666.0
View Code
Observer源码:
1 public classObservable {2 private boolean changed = false;//判断观察对象是否发生变化
3 private Vector obs;//观察者队列
4 publicObservable() {5 obs = newVector();6 }7
8
9 public synchronized voidaddObserver(Observer o) {10 if (o == null)11 throw newNullPointerException();12 if (!obs.contains(o)) {13 obs.addElement(o);14 }15 }16
17 public synchronized voiddeleteObserver(Observer o) {18 obs.removeElement(o);19 }20
21
22 public voidnotifyObservers() {23 notifyObservers(null);24 }25
26 //通知观察者
27 public voidnotifyObservers(Object arg) {28
29 Object[] arrLocal;30
31 synchronized (this) {32
33 if (!changed)34 return;35 arrLocal =obs.toArray();36 clearChanged();37 }38
39 for (int i = arrLocal.length-1; i>=0; i--)40 ((Observer)arrLocal[i]).update(this, arg);41 }42
43
44 public synchronized voiddeleteObservers() {45 obs.removeAllElements();46 }47
48
49 protected synchronized voidsetChanged() {50 changed = true;51 }52
53
54 protected synchronized voidclearChanged() {55 changed = false;56 }57
58
59 public synchronized booleanhasChanged() {60 returnchanged;61 }62
63
64 public synchronized intcountObservers() {65 returnobs.size();66 }67 }
View Code
可以发现JDK中实现的观察者模式,用法简单功能强大,和我们上面写的观察者模式实现原理是一样的。观察者模式可以用于事件监听、通知发布等场合,可以确保观察者在不适用轮询监控的情况下,可以及时得到相关消息和事件。