观察者模式:定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。(ps:其实本质上并不是自动更新,还是由主体来触发更新的)
设计原则:为了交互对象之间的松耦合设计而努力。
1 package pattern.observer;
2
3 /**
4 * 主体公共接口
5 * @author CS_Xiaochao
6 *
7 */
8 public interface Subject {
9
10 void registerObserver(Observers observers);
11 void removeObserver(Observers observers);
12 void notifyObserver(int tempurature);
13
14 }
1 package pattern.observer;
2
3 import java.util.LinkedList;
4 import java.util.List;
5
6 /**
7 * 实现接口的一个主体
8 * @author CS_Xiaochao
9 *
10 */
11 public class WeatherData implements Subject {
12
13 private Observers observers;
14 private List<Observers> list;
15
16 public WeatherData(){
17 if(list == null){
18 list = new LinkedList<Observers>();
19 }
20 }
21
22 @Override
23 public void registerObserver(Observers observers) {
24 if(list.add(observers)){
25 System.out.println("注册观察者:" + observers + " 成功!");
26 }
27 }
28
29 @Override
30 public void removeObserver(Observers observers) {
31 if(list.remove(observers)){
32 System.out.println("注销观察者:" + observers + " 成功!");
33 }
34 }
35
36 @Override
37 public void notifyObserver(int tempurature) {
38 for(int i = 0; i < list.size(); i++){
39 list.get(i).update(tempurature);
40 }
41 }
42
43 }
1 package pattern.observer;
2
3 /**
4 * 观察者公共接口
5 * @author CS_Xiaochao
6 *
7 */
8 public interface Observers {
9 void update(double tempurature);
10 }
1 package pattern.observer;
2
3 public class TemperatureBoard implements Observers {
4
5 @Override
6 public void update(double tempurature) {
7 System.out.println("当前温度:" + tempurature);
8 }
9
10 }
1 package pattern.observer;
2
3 public class ComitityBoard implements Observers {
4
5 @Override
6 public void update(double tempurature) {
7 System.out.println("当前湿度为:" + Math.sqrt(tempurature));
8 }
9
10 }
1 package pattern.observer;
2
3 import java.util.Random;
4
5 public class ObserverDemo {
6
7 /**
8 * @param args
9 */
10 public static void main(String[] args) {
11
12 WeatherData weatherData = new WeatherData();
13
14 Observers temperatureObserver = new TemperatureBoard();
15 Observers comitityObserver = new ComitityBoard();
16
17 weatherData.registerObserver(temperatureObserver);
18 weatherData.registerObserver(comitityObserver);
19
20 //weatherData.removeObserver(comitityObserver);
21
22 Random random = new Random();
23 for(int i = 0 ; i < 100; i++){
24 if(random.nextInt(100) % 2 == 0){
25 weatherData.notifyObserver(random.nextInt(100));
26 }
27 }
28 }
29
30 }
观察者模式是一对多的依赖关系,其中“一”对应主体,“多”对应观察者(们),也就是说当主体中的内容发生变化时,通过某种机制来通知观察者们,让观察者做一些应对的动作。观察者具有一个公共的接口,接口中定义了观察者公共的方法。所有具体的观察者都可以根据自身的特点来实现接口中的方法。主体中包含了的方法主要是:注册一个观察者,删除一个观察者,通知观察者。主体中存放了所有已注册的观察者的对象,当调用注册方法的时候,就往主体中添加一个新的观察者对象,当调用删除方法时,则将指定的观察者对象从主体中删除,当调用通知方法时,则用此用主体中保存的观察者对象来调用观察者的方法,从而实现当主体发生改变时,观察者作出相应应对的效果。实际上观察者模式往往给人的错觉是:观察者在实时的监听主体,一旦主体有变化,则作出相应应对。事实上观察者并没有去实时的监听主体,而是当主体发生改变的时候,主动的去“通知”观察者们作出相应动作(这里说通知,还不是很恰当,因为观察者每一次作出相应举动,都是主体主动利用存储的观察者对象来调用观察者的方法的,观察者始终处于一个被动的角色,主体利用一个共同的接口来更新观察者)。
补充:上面主要讲了主体(主题、可观察者)向观察者推送数据的方式,实际上也可以让观察者们主动去从主体那里去拿数据,只需要在每一个观察者中保存一份主体的对象,然后调用主体的方法来获得数据即可。但是一般认为被观察者向观察者“推”数据的方式比观察者们从可观察者那里“拿”数据的方式要好。
Java中内置了观察者模式(本人不推荐去使用,自己去实现更加灵活,能加深对于该模式的理解,况且该模式在思想上并不是很难。),Java程序设计语言在很多地方也采用了观察者模式,比较经典的就是在Swing中各种组件对于用户事件的监听。
1 package java.util;
2
3 public class Observable {
4 private boolean changed = false;
5 private Vector obs;
6
7 /** Construct an Observable with zero Observers. */
8
9 public Observable() {
10 obs = new Vector();
11 }
12
13 /**
14 * Adds an observer to the set of observers for this object, provided
15 * that it is not the same as some observer already in the set.
16 * The order in which notifications will be delivered to multiple
17 * observers is not specified. See the class comment.
18 *
19 * @param o an observer to be added.
20 * @throws NullPointerException if the parameter o is null.
21 */
22 public synchronized void addObserver(Observer o) {
23 if (o == null)
24 throw new NullPointerException();
25 if (!obs.contains(o)) {
26 obs.addElement(o);
27 }
28 }
29
30 /**
31 * Deletes an observer from the set of observers of this object.
32 * Passing <CODE>null</CODE> to this method will have no effect.
33 * @param o the observer to be deleted.
34 */
35 public synchronized void deleteObserver(Observer o) {
36 obs.removeElement(o);
37 }
38
39 /**
40 * If this object has changed, as indicated by the
41 * <code>hasChanged</code> method, then notify all of its observers
42 * and then call the <code>clearChanged</code> method to
43 * indicate that this object has no longer changed.
44 * <p>
45 * Each observer has its <code>update</code> method called with two
46 * arguments: this observable object and <code>null</code>. In other
47 * words, this method is equivalent to:
48 * <blockquote><tt>
49 * notifyObservers(null)</tt></blockquote>
50 *
51 * @see java.util.Observable#clearChanged()
52 * @see java.util.Observable#hasChanged()
53 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
54 */
55 public void notifyObservers() {
56 notifyObservers(null);
57 }
58
59 /**
60 * If this object has changed, as indicated by the
61 * <code>hasChanged</code> method, then notify all of its observers
62 * and then call the <code>clearChanged</code> method to indicate
63 * that this object has no longer changed.
64 * <p>
65 * Each observer has its <code>update</code> method called with two
66 * arguments: this observable object and the <code>arg</code> argument.
67 *
68 * @param arg any object.
69 * @see java.util.Observable#clearChanged()
70 * @see java.util.Observable#hasChanged()
71 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
72 */
73 public void notifyObservers(Object arg) {
74 /*
75 * a temporary array buffer, used as a snapshot of the state of
76 * current Observers.
77 */
78 Object[] arrLocal;
79
80 synchronized (this) {
81 /* We don't want the Observer doing callbacks into
82 * arbitrary code while holding its own Monitor.
83 * The code where we extract each Observable from
84 * the Vector and store the state of the Observer
85 * needs synchronization, but notifying observers
86 * does not (should not). The worst result of any
87 * potential race-condition here is that:
88 * 1) a newly-added Observer will miss a
89 * notification in progress
90 * 2) a recently unregistered Observer will be
91 * wrongly notified when it doesn't care
92 */
93 if (!changed)
94 return;
95 arrLocal = obs.toArray();
96 clearChanged();
97 }
98
99 for (int i = arrLocal.length-1; i>=0; i--)
100 ((Observer)arrLocal[i]).update(this, arg);
101 }
102
103 /**
104 * Clears the observer list so that this object no longer has any observers.
105 */
106 public synchronized void deleteObservers() {
107 obs.removeAllElements();
108 }
109
110 /**
111 * Marks this <tt>Observable</tt> object as having been changed; the
112 * <tt>hasChanged</tt> method will now return <tt>true</tt>.
113 */
114 protected synchronized void setChanged() {
115 changed = true;
116 }
117
118 /**
119 * Indicates that this object has no longer changed, or that it has
120 * already notified all of its observers of its most recent change,
121 * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
122 * This method is called automatically by the
123 * <code>notifyObservers</code> methods.
124 *
125 * @see java.util.Observable#notifyObservers()
126 * @see java.util.Observable#notifyObservers(java.lang.Object)
127 */
128 protected synchronized void clearChanged() {
129 changed = false;
130 }
131
132 /**
133 * Tests if this object has changed.
134 *
135 * @return <code>true</code> if and only if the <code>setChanged</code>
136 * method has been called more recently than the
137 * <code>clearChanged</code> method on this object;
138 * <code>false</code> otherwise.
139 * @see java.util.Observable#clearChanged()
140 * @see java.util.Observable#setChanged()
141 */
142 public synchronized boolean hasChanged() {
143 return changed;
144 }
145
146 /**
147 * Returns the number of observers of this <tt>Observable</tt> object.
148 *
149 * @return the number of observers of this object.
150 */
151 public synchronized int countObservers() {
152 return obs.size();
153 }
154 }
1 package java.util;
2
3 public interface Observer {
4 /**
5 * This method is called whenever the observed object is changed. An
6 * application calls an <tt>Observable</tt> object's
7 * <code>notifyObservers</code> method to have all the object's
8 * observers notified of the change.
9 *
10 * @param o the observable object.
11 * @param arg an argument passed to the <code>notifyObservers</code>
12 * method.
13 */
14 void update(Observable o, Object arg);
15 }