读书笔记_java设计模式深入研究 第五章 观察者模式 Observer

1,观察者模式适合解决多种对象跟踪一个对象数据变化的程序结构问题,一个称作“主题”的对象和若干个称作“观察者”的对象。在主题对象更新后会通知所有的观察者,使他们自动更新自己。

2,观察者UML类图:

读书笔记_java设计模式深入研究 第五章  观察者模式 Observer

读书笔记_java设计模式深入研究 第五章  观察者模式 Observer

3,角色解释:

-1,抽象观察者(IObserver):为所有具体观察者定义接口,在得到主题通知的时候,更新观察者自身数据。

-2,抽象主题(ISubject):使用数组引用维护一组观察者对象,可以增加和删除观察者,同时同志观察者自身的改变。

-3,观察者(Observer):具体观察对象,实现对应接口方法,根据主题对象的更新而更新自身。

-4,主题(Subject):具体主题。

4,简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 *
 * @(#) IObserver.java
 * @Package pattern.chp05.observer.simpledemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.simpledemo;
 
/**
 *  类描述:观察者接口
 *
 *  @author:  Jing
 *  @version  $Id: Exp$
 *
 *  History:  Dec 22, 2014 4:01:33 PM   Jing   Created.
 *          
 */
public interface IObserver {
    /**
     *
     * 方法说明:刷新数据
     *
     * Author:       Jing               
     * Create Date:   Dec 22, 2014 4:02:59 PM
     *
     * @param data
     * @return void
     */
    public void refresh(String data);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
 *
 * @(#) ISubject.java
 * @Package pattern.chp05.observer.simpledemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.simpledemo;
 
/**
 * 类描述:主题接口
 *
 * @author: Jing
 * @version $Id: Exp$
 *
 * History: Dec 22, 2014 4:02:16 PM Jing Created.
 *
 */
public interface ISubject {
    /**
     *
     * 方法说明:注册观察者
     *
     * Author: Jing Create Date: Dec 22, 2014 4:02:48 PM
     *
     * @param obs
     * @return void
     */
    public void register(IObserver obs);
    /**
     *
     * 方法说明:撤销观察者
     *
     * Author:       Jing               
     * Create Date:   Dec 22, 2014 4:03:38 PM
     *
     * @param obs
     * @return void
     */
    public void unregister(IObserver obs);
    /**
     *
     * 方法说明:通知观察者自身数据改变
     *
     * Author:       Jing               
     * Create Date:   Dec 22, 2014 4:04:02 PM
     *
     * @return void
     */
    public void notifyObserver();
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 *
 * @(#) Observer.java
 * @Package pattern.chp05.observer.simpledemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.simpledemo;
 
/**
 *  类描述:观察者
 *
 *  @author:  Jing
 *  @version  $Id: Exp$
 *
 *  History:  Dec 22, 2014 4:48:01 PM   Jing   Created.
 *          
 */
public class Observer implements IObserver {
 
    public void refresh(String data) {
         
        System.out.println(this.toString() + " received data: " + data);
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 *
 * @(#) Subject.java
 * @Package pattern.chp05.observer.simpledemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.simpledemo;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 类描述:具体主题
 *
 * @author: Jing
 * @version $Id: Exp$
 *
 * History: Dec 22, 2014 4:04:31 PM Jing Created.
 *
 */
public class Subject implements ISubject {
 
    private List<IObserver> obvers = new ArrayList<IObserver>();
 
    private String data;
 
    public void notifyObserver() {
 
        for (IObserver o : obvers) {
 
            o.refresh(data);
        }
    }
 
    public void register(IObserver obs) {
 
        obvers.add(obs);
    }
 
    public void unregister(IObserver obs) {
 
        if (obvers.contains(obs)) {
 
            obvers.remove(obs);
        }
    }
 
    /**
     * @return the obvers
     */
    public List<IObserver> getObvers() {
        return obvers;
    }
 
    /**
     * @param obvers
     *            the obvers to set
     */
    public void setObvers(List<IObserver> obvers) {
        this.obvers = obvers;
    }
 
    /**
     * @return the data
     */
    public String getData() {
        return data;
    }
 
    /**
     * @param data
     *            the data to set
     */
    public void setData(String data) {
        this.data = data;
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 *
 * @(#) TestMain.java
 * @Package pattern.chp05.observer.simpledemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.simpledemo;
 
import org.junit.Test;
 
/**
 *  类描述:
 *
 *  @author:  Jing
 *  @version  $Id: Exp$
 *
 *  History:  Dec 22, 2014 4:51:38 PM   Jing   Created.
 *          
 */
public class TestMain {
     
    @Test
    public void testMain() throws Exception {
         
        IObserver obs = new Observer();
        Subject subject = new Subject();
        subject.register(obs);
        subject.setData("hi");
        subject.notifyObserver();
    }
}

5,JDK中的观察者模式:

         java.util.Observable :

1
2
3
4
5
主题对象,一个Observable对象可以有一个或多个观察者,观察者可以是实现了Observer接口的任意对象,一个Observable实例 改变后,调用notifyObservers方法的应用程序会通过调用观察者的update方法来通知该实例发生了改变。
 
       默认按照注册的重要性来通知Observers。注意此通知机制与线程无关,并且与Object类的wait和notify机制完全独立。
 

     新建Observable对象时,其观察集合是空的。当且仅当equals方法为两个观察者返回true时,才认为他们是相同的。

--引用自JDK 1.6.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void addObserver(Observer o)
          如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。
protected  void clearChanged()
          指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false
int countObservers()
          返回 Observable 对象的观察者数目。
void deleteObserver(Observer o)
          从对象的观察者集合中删除某个观察者。
void deleteObservers()
          清除观察者列表,使此对象不再有任何观察者。
boolean hasChanged()
          测试对象是否改变。
void notifyObservers()
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
void notifyObservers(Object arg)
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
protected  void setChanged()
          标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true

      java.util.Observer: 

1
一个观察者要得到Observable对象更改通知时,可实现此接口
1
2
3
4
5
6
7
8
update
 
void update(Observable o,
            Object arg)
只要改变了 observable 对象就调用此方法。应用程序调用 Observable 对象的 notifyObservers 方法,以便向所有该对象的观察者通知此改变。
参数:
o - observable 对象。
arg - 传递给 notifyObservers 方法的参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 *
 * @(#) Subject.java
 * @Package pattern.chp05.observer.jdkdemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.jdkdemo;
 
import java.util.Observable;
 
/**
 * 类描述:主题对象
 *
 * @author: Jing
 * @version $Id: Exp$
 *
 * History: Dec 22, 2014 5:34:03 PM Jing Created.
 *
 */
public class Subject extends Observable {
 
    String data;
 
    public String getData() {
        return data;
    }
 
    public void setData(String data) {
        this.data = data;
        setChanged();//设置数据更新标志
        notifyObservers(null);
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 *
 * @(#) OneObserver.java
 * @Package pattern.chp05.observer.jdkdemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.jdkdemo;
 
import java.util.Observable;
 
/**
 *  类描述:观察者
 *
 *  @author:  Jing
 *  @version  $Id: Exp$
 *
 *  History:  Dec 22, 2014 5:35:56 PM   Jing   Created.
 *          
 */
public class OneObserver implements java.util.Observer {
 
    public void update(Observable o, Object arg) {
         
        Subject subject = (Subject)o;
        System.out.println("This data is :" + subject.getData());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 *
 * @(#) Test.java
 * @Package pattern.chp05.observer.jdkdemo
 *
 * Copyright © JING Corporation. All rights reserved.
 *
 */
 
package pattern.chp05.observer.jdkdemo;
 
import java.util.Observer;
 
/**
 *  类描述:
 *
 *  @author:  Jing
 *  @version  $Id: Exp$
 *
 *  History:  Dec 22, 2014 5:37:41 PM   Jing   Created.
 *          
 */
public class Test {
 
    @org.junit.Test
    public void testMain(){
         
        Observer obj = new OneObserver();
        Subject s = new Subject();
        s.addObserver(obj);
        s.setData("hello");
    }
}

6,Observerable类和Observer接口代码分析

     Observer接口:

public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
Observerable类:
使用一组线程安全的方法,来实现对应观察者的增加移除以及通知。
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its
* observers and then call the <code>clearChanged</code> method to
* indicate that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with
* two arguments: this observable object and the <code>arg</code>
* argument.
*
* @param arg
* any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable,
* java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of current
* Observers.
*/
Object[] arrLocal;
 
synchronized (this) {
/*
* We don't want the Observer doing callbacks into arbitrary code
* while holding its own Monitor. The code where we extract each
* Observable from the Vector and store the state of the Observer
* needs synchronization, but notifying observers does not (should
* not). The worst result of any potential race-condition here is
* that: 1) a newly-added Observer will miss a notification in
* progress 2) a recently unregistered Observer will be wrongly
* notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
 
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
7,应用:机房温度检测仿真
   定间隔采集温度数值
   记录采集的温度数值
   当温度连续超过比较值n次,启动报警信息。
/**
*
* @(#) AbnormalObserver.java
* @Package pattern.chp05.observer.demo
*
* Copyright © JING Corporation. All rights reserved.
*
*/
 
package pattern.chp05.observer.demo;
 
import java.util.Observable;
import java.util.Observer;
 
/**
* 类描述:异常数据观察者
*
* @author: Jing
* @version $Id: Exp$
*
* History: Dec 23, 2014 10:31:08 AM Jing Created.
*
*/
public class AbnormalObserver implements Observer {
 
private int c = 0;// 温度异常数累计
 
public void update(Observable o, Object arg) {
 
Subject subject = (Subject) o;
Factor factor = (Factor) arg;
 
if (subject.getData() < factor.getLimie()) {// 小于预警值,则异常级数归0
 
c = 0;
return;
}
c++;
 
if (c == factor.getTimes()) {// 符合预警次数
 
// some code 预警
 
c = 0;// 计数清零
}
 
}
 
}
/**
*
* @(#) DataObserver.java
* @Package pattern.chp05.observer.demo
*
* Copyright © JING Corporation. All rights reserved.
*
*/
 
package pattern.chp05.observer.demo;
 
import java.util.Date;
import java.util.Observable;
import java.util.Observer;
 
/**
* 类描述:数据记录观察者
*
* @author: Jing
* @version $Id: Exp$
*
* History: Dec 23, 2014 10:28:11 AM Jing Created.
*
*/
public class DataObserver implements Observer {
 
public void update(Observable o, Object arg) {
Subject subject = (Subject)o;
String sql = "insert into xxxx values " + subject.getData() + (new Date()).toString() ;//模拟sql语句
System.out.println("执行: " + sql );
}
 
}
/**
*
* @(#) Subject.java
* @Package pattern.chp05.observer.demo
*
* Copyright © JING Corporation. All rights reserved.
*
*/
 
package pattern.chp05.observer.demo;
 
/**
* 类描述:主题类
*
* @author: Jing
* @version $Id: Exp$
*
* History: Dec 23, 2014 10:24:38 AM Jing Created.
*
*/
public class Subject extends java.util.Observable {
 
private int data;
private Factor factor;
 
/**
*
* 方法说明:数据更改
*
* Author: Jing Create Date: Dec 23, 2014 10:27:15 AM
*
* @param data
* @return void
*/
public void setData(int data) {
this.data = data;
setChanged();
notifyObservers(factor);
}
 
/**
* @return the factor
*/
public Factor getFactor() {
return factor;
}
 
/**
* @param factor
* the factor to set
*/
public void setFactor(Factor factor) {
this.factor = factor;
}
 
/**
* @return the data
*/
public int getData() {
return data;
}
 
}