- 观察者模式介绍
观察者模式是一种非常有用的设计模式,在软件系统中,当一个对象的行为依赖于另一个对象的状态时,观察者模式就非常有用。如果不适用观察者模式,而实现类似的功能,可能就需要另外启动一个线程不停地监听另一个对象的状态,这样会得不偿失。如果在一个复杂的系统中,可能就需要开启很多的线程来监听对象状态的变化,这样会使系统的性能产生额外的负担。而观察者模式就可以在单线程下使某一对象及时得知所依赖对象状态的变化而做出行为。
观察者模式的经典结构:
其中ISubject是观察对象(被观察者对象),它维持着一个观察者对象列表,可以增加或删除观察者。IObserver是观察者,它依赖于ISubject对象状态的变化而做出行为。当ISubject对象的状态发生变化时,它可以通过inform()方法通知观察者。
观察者模式的主要角色功能如下图:
- 观察者实例
现在简单实现一个观察者的小例子。
主题接口:
1 public interface ISubject { 2 void attach(IObserver observer); 3 void detach(IObserver observer); 4 void inform(); 5 }
观察者接口:
1 public interface IObserver { 2 void update(Event event); 3 }
事件(对应现实中的点击等事件也可以理解为上文中说到的状态变化):
1 public class Event { 2 3 }
具体的主题实现:
1 public class ConcreteSubject implements ISubject { 2 Vector<IObserver> obversers = new Vector<IObserver>();//观察者队列 3 @Override 4 public void attach(IObserver observer) { 5 obversers.add(observer); 6 } 7 8 @Override 9 public void detach(IObserver observer) { 10 obversers.remove(observer); 11 } 12 13 @Override 14 public void inform() { 15 Event event = new Event(); 16 for(IObserver obverser:obversers){ 17 obverser.update(event); 18 } 19 } 20 21 }
具体的观察者:
1 public class ConcreteObserver implements IObserver { 2 3 @Override 4 public void update(Event event) { 5 System.out.println("ConcreteObserver.update()"); 6 } 7 8 }
测试代码:
public class Test { public static void main(String[] args) { IObserver observer1 = new ConcreteObserver(); IObserver observer2 = new ConcreteObserver(); ISubject subject = new ConcreteSubject(); subject.attach(observer1); subject.attach(observer2); subject.inform(); } }
可以看出,通过被观察者状态变化而调用某一方法使观察者收到通知而做出反应,通过委托降低了代码的耦合度。
观察者模式十分常用,以致于JDK内部就为开发人员准备了一套观察者模式的实现。在java.util包中,就包括了Obserable类和Observer接口。在Observable中就实现了观察对象的主要功能,如:添加观察者、删除观察者和通知观察者等。Observer是观察者接口,它的update方法会在Obserable类的notifyObservers()中被回调以获得最新的状态变化。
以现在比较火热的购房作为观察者模式的一个例子:现在很多购房者关注房价的变化,每当房价发生变动的时候,购房者就会收到通知。这样购房者就是观察者,他们关注着房子的价格。
观察对象房子代码:
1 public class House extends Observable{ 2 private float price; 3 4 public House(float price) { 5 super(); 6 this.price = price; 7 } 8 9 public float getPrice() { 10 return price; 11 } 12 13 public void setPrice(float price) { 14 super.setChanged();//设置变化点 15 super.notifyObservers(price);//价格变动 16 this.price = price; 17 } 18 19 @Override 20 public String toString() { 21 // TODO Auto-generated method stub 22 return "房子的价格为:"+this.price; 23 } 24 }
观察者购房者代码:
1 public class CustomerObserver implements Observer{ 2 3 private String name; 4 5 public CustomerObserver(String name) { 6 super(); 7 this.name = name; 8 } 9 10 @Override 11 public void update(Observable o, Object arg) { 12 if (arg instanceof Float) { 13 System.out.println(this.name+"观察到房子价格变动为:"+arg); 14 } 15 } 16 }
测试代码:
1 public class Test1 { 2 public static void main(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
Observer源码:
1 public class Observable { 2 private boolean changed = false;//判断观察对象是否发生变化 3 private Vector obs;//观察者队列 4 public Observable() { 5 obs = new Vector(); 6 } 7 8 9 public synchronized void addObserver(Observer o) { 10 if (o == null) 11 throw new NullPointerException(); 12 if (!obs.contains(o)) { 13 obs.addElement(o); 14 } 15 } 16 17 public synchronized void deleteObserver(Observer o) { 18 obs.removeElement(o); 19 } 20 21 22 public void notifyObservers() { 23 notifyObservers(null); 24 } 25 26 //通知观察者 27 public void notifyObservers(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 void deleteObservers() { 45 obs.removeAllElements(); 46 } 47 48 49 protected synchronized void setChanged() { 50 changed = true; 51 } 52 53 54 protected synchronized void clearChanged() { 55 changed = false; 56 } 57 58 59 public synchronized boolean hasChanged() { 60 return changed; 61 } 62 63 64 public synchronized int countObservers() { 65 return obs.size(); 66 } 67 }
可以发现JDK中实现的观察者模式,用法简单功能强大,和我们上面写的观察者模式实现原理是一样的。观察者模式可以用于事件监听、通知发布等场合,可以确保观察者在不适用轮询监控的情况下,可以及时得到相关消息和事件。