设计模式(二)The Observer Pattern 观察者模式

问题引入

        生成一个公告板显示当时的天气状况,当天气状况发生改变的时候公告板可以实时的更新。

模式定义

        定义对象之间的一对多的依赖,当一个对象改变状态时,它的所有依赖者都会自动收到通知并自动更新。

认识模式

        该模式在生活中是很常见的。想想生活中的各种各样的检测系统,报警系统,一旦有重要事件发生时,有关系统总能及时的收到通知,这就是观察者模式。

问题解决

        关于观察者模式,java实际上给了我们内置的支持(可以看出该模式还是很常用的吧!)但是我们经常会自己实现。为什么呢?我们后面会给出答案。

        被观察者我们称之为主题(Subject),相应的有观察者(Observer)。

一、自定义实现

      1)  Subject,Observer我们都定义为接口

?
1
2
3
4
5
6
7
8
9
10
11
package  my.oschina.net.design.observer.owndesign;
 
public  interface  Subject {
     public  void  registerObserver(Observer o);
     public  void  removeObserver(Observer o);
     public  void  notifyObserver();    
}
 
public  interface  Observer {
     void  update(Subject sub);
}

    2)实现Subject和Observer接口(主题与观察者的实现)    

        a)主题实现

?
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
package  my.oschina.net.design.observer.finaldesign;
 
import  java.util.ArrayList;
 
public  class  WeatherData  implements  Subject{
     
     //被观测的指标数据
     private  float  temp;
     private  float  humidity;
     private  float  pressure;
     
     //维护一个订阅过的Observer列表
         private  ArrayList<Observer> Observers;
     
     public  WeatherData()
     {
         this .Observers =  new  ArrayList<Observer>();
     }
 
     @Override
     //增加Observer
     public  void  registerObserver(Observer o) {
         // TODO Auto-generated method stub
         Observers.add(o);      
     }
 
     @Override
     //移除部分Observer
     public  void  removeObserver(Observer o) {
         // TODO Auto-generated method stub
         int  i = Observers.indexOf(o);
         if (i != - 1 )
             Observers.remove(Observers.indexOf(o));    
     }
     
     @Override
     //通知订阅过的Observer
     public  void  notifyObserver() {
         // TODO Auto-generated method stub
         for (Observer o : Observers)
         {
             o.update( this );
         }
     }
     
     public  void  setStatus( float  temp,  float  humidity,  float  pressure)
     {
         this .temp = temp;
         this .humidity = humidity;
         this .pressure = pressure;
         
         statusChanged();
     }
     
     public  void  statusChanged()
     {
         notifyObserver();
     }
     
     float  getTemp()
     {
         return  temp;
     }
     
     float  getHumidity()
     {
         return  humidity;
     }
     
     float  getPressure()
     {
         return  pressure;
     }  
}

          b)观察者实现

?
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
package  my.oschina.net.design.observer.finaldesign;
 
public  class  CurrentConditionDisplay  implements  Observer,Display{
     
     //接收被观测者发过来的数据
     private  float  temp;
     private  float  humidity;
     private  float  pressure;
     //保存这个主题对象,可能后续有退订的需求
     private  WeatherData weatherData;
     
     public  CurrentConditionDisplay(WeatherData weahterdata)
     {
         this .weatherData = weahterdata;
         weatherData.registerObserver( this );
     }
     
     @Override
     public  void  update(Subject sub) {
         // TODO Auto-generated method stub
         
         if (sub  instanceof  WeatherData)
         {
             WeatherData weatherdata = (WeatherData)sub;
             this .temp = weatherdata.getTemp();
             this .humidity = weatherdata.getHumidity();
             this .pressure = weatherdata.getPressure();
         }
         
         display();
     }
 
     @Override
     public  void  display() {
         // TODO Auto-generated method stub
     System.out.println( "Temp --> "  + temp +  "humidity --> "  +humidity +  "pressure -->"  + pressure);
     }
 
}

        3)Test一下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package  my.oschina.net.design.observer.finaldesign;
 
public  class  ObserverTest1 {
 
     public  static  void  main(String[] args) {
         // TODO Auto-generated method stub
         WeatherData weatherdata =  new  WeatherData();
         
         CurrentConditionDisplay cc =  new  CurrentConditionDisplay(weatherdata);
         
         weatherdata.setStatus( 12 12 12 );
         weatherdata.setStatus( 13 13 13 );
         weatherdata.setStatus( 14 14 14 );       
     }
}

        4)结果截图

二、java内置实现

        在java的java.util 包(pac1kage)中包含了最基本的Observable类(可观察,通过继承方式获得其方法和属性)Observer接口(观察),对你没有看错,我也没有写错,的确是Observable类Observer接口,他们类似与我们上述自己定义的Subject和Observer接口,由于是java内置,有的时候使用它们的话真的是挺简单的,因为有好多的功能java本身已经为我们写好了!

        其实这里你已经可以明白这种内置实现的弊端了,对就是因为Observable是个类!在java中只支持单继承,所以啊,这就限制了继承他的类使用的灵活性!

java内置的不同

    a)关于主题对象

        当我们自定义观察者的时候当需要通知观察者的时候我们直接调用notifyO不servers()方法即可, 但是java内置的方法不是这样的,我们需要两步走:

                1>调用setChanged()方法,标记状态已改变;

                2>调用notifyObserver()方法,完成通知的工作。

 深入-------->setChanged()

                我们来看看Observable内部的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    setChanged()
    {
        cahnged =  true ;
    }
   
    notifyObservers(Object arg)
    {
        if (cahnged)
        {
            for  every obsrver on the list
            {
                call update( this , arg)
            }
            cahngd =  false ;
        }
    }
    
     notifyObservers()
     {
         notifyObservers( null )
     }

         看到这里有人可能要问了:为什么要设置一个标志呢???仔细想想,假设你是公司老总,每天要批一系列文件,好了,现在秘书送来一份文件你批了,一分钟没到,又有新的文件产生了,秘书又送了过来,然后。。。然后。。。你受得了吗?你可能会对秘书说:小李啊,这个文件你给我每50份一批给我送过来,我一并批阅!有时候我们并不希望被观察者有一丝的变化马上就通知我们,我们可以等被观察者达到一定的程度的时候(比如说等温度上升5℃以内不必通知系统,一旦超过5℃就通知系统!)再通知我们,你可以想想这样好处很多!所以当达到标准,我们需要通知观察者的时候调用setChanged()方法还真是不错的哦!

    b)关于观察者

                update的方法略有不同update(Observable o, Object arg),第一个参数是主题本身,第二个参数为传入notifyObserver()的数据对象,没有为空。这里就来决定是由被观察者push数据,还是有观察者自己pull数据。

代码走起         

1)被观察者实现(注意import相应的package)

?
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
package  my.oschina.net.design.observer.javautil;
 
import  java.util.Observable;
import  java.util.Observer;
/**
  * 这种方式有一个弊端就是说Observable是一个 类而不是一个接口因此它限制了这个类的使用
  * @author Eswin
  *
  */
public  class  WeatherData  extends  Observable{
     
     //被观测的指标数据
     private  float  temp;
     private  float  humidity;
     private  float  pressure;
 
     public  WeatherData(){}
     
     public  void  setStatus( float  temp,  float  humidity,  float  pressure)
     {
         this .temp = temp;
         this .humidity = humidity;
         this .pressure = pressure;
         
         statusChanged();
     }
     
     public  void  statusChanged()
     {
         setChanged();
         notifyObservers();
     }
     
     public  float  getTemp()
     {
         return  temp;
     }
     
     public  float  getHumidity()
     {
         return  humidity;
     }
     
     public  float  getPressure()
     {
         return  pressure;
     }
 
     
}

2)观察者实现

?
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
package  my.oschina.net.design.observer.javautil;
 
import  java.util.Observable;
import  java.util.Observer;
 
import  my.oschina.net.design.observer.owndesign.Display;
 
public  class  CurrentConditionDisplay  implements  Observer, Display{
 
     private  float  temp;
     private  float  humidity;
     private  float  pressure;
     
     private  Observable observable;
     
     public  CurrentConditionDisplay(Observable observable)
     {
         this .observable = observable;
         observable.addObserver( this );
         
     }
     
     @Override
     public  void  update(Observable o, Object arg) {
         // TODO Auto-generated method stub
         if (o  instanceof  WeatherData)
         {
             WeatherData weatherdata = (WeatherData)o;
             this .temp = weatherdata.getTemp();
             this .humidity = weatherdata.getHumidity();
             this .pressure = weatherdata.getPressure();
         }
         
         display();
         
     }
 
     @Override
     public  void  display() {
         // TODO Auto-generated method stub
         System.out.println( "Temp --> "  + temp +  "humidity --> "  +humidity +  "pressure -->"  + pressure);
     }
 
}

3)Test一下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package  my.oschina.net.design.observer.javautil;
 
public  class  ObserverTest2 {
     public  static  void  main(String[] args) {
         // TODO Auto-generated method stub     
             WeatherData weatherdata =  new  WeatherData();
                     
         CurrentConditionDisplay cc =  new  CurrentConditionDisplay(weatherdata);
         
         weatherdata.setStatus( 12 12 12 );
         weatherdata.setStatus( 13 13 13 );
         weatherdata.setStatus( 14 14 14 );
     }
}

 4)结果截图

模式延伸

    其实我们我们在编程的过程中有很多时候都运用到了观察者模式,想想Swing,还有JavaBean,还有RMI。

模式建议

    1)要注意Observable这个类所带来的问题;

Observable is a class

You already know from our principles this is a bad idea, but what harm does it reallycause?

First, because Observable is a class, you have to subclass it. That means you can’t add
on the Observable behavior to an existing class that already extends another superclass.This limits its reuse potential (and isn’t that why we are using patterns in the first place?).

Second, because there isn’t an Observable interface, you can’t even create your ownimplementation that plays well with Java’s built-in Observer API. Nor do you havethe option of swapping out the java.util implementation for another (say, a new, multi-threaded implementation).

Observable protects crucial methods

If you look at the Observable API, the setChanged() method is protected. So what? Well,this means you can’t call setChanged() unless you’ve subclassed Observable. This meansyou can’t even create an instance of the Observable class and compose it with your ownobjects, you have to subclass. The design violates a second design principle here...favorcomposition over inheritance. 

    2)有必要的话自己实现Observable也就是主题,很简单(三个方法实现就可以了)。



安卓中的应用:

观察者模式,是一种非常常见的设计模式,在很多系统中随处可见,尤其是涉及到数据状态发生变化需要通知的情况下。
本文以AbstractCursor为例子,展开分析。
观察者模式,Observer Pattern,是一个很实用的模式,本人曾经接触到的各种平台以及曾经参与项目中打印模板解释器中都用到了此模式。

1.意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
热门词汇:依赖 发布-订阅 事件 通知 更新 监听 

2.结构

Android SDK源码观察设计模式
这是一个最简单的观察者模式,目标对象能够添加和删除观察者,当自己某种状态或者行为发生改变时,可通过notify通知注册的观察者进行更新操作。
分析AbstractCursor的具体情况,我们发现实际工作有时需要对观察者进行统一管理,甚至观察者类型有很多种而又可以分成几个系列,这个时候是要复杂的多,通过合理的分层这个问题很好解决。下面根据具体情况,我们画出android中abstractCurosr中用到的观察者模式结构图:

Android SDK源码观察设计模式

观察者分成了两个系列。

3.代码

列举其中相关核心代码如下:

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
public  abstract  class AbstractCursor  {
     //定义管理器
    DataSetObservable mDataSetObservable  =  new DataSetObservable ( ) ;
    ContentObservable mContentObservable  =  new ContentObservable ( ) ;
     
     //注册和卸载两类观察者
     public  void registerContentObserver (ContentObserver observer )  {
        mContentObservable. registerObserver (observer ) ;
     }
 
     public  void unregisterContentObserver (ContentObserver observer )  {
         // cursor will unregister all observers when it close
         if  ( !mClosed )  {
            mContentObservable. unregisterObserver (observer ) ;
         }
     }
 
     public  void registerDataSetObserver (DataSetObserver observer )  {
        mDataSetObservable. registerObserver (observer ) ;
         
     }
 
     public  void unregisterDataSetObserver (DataSetObserver observer )  {
        mDataSetObservable. unregisterObserver (observer ) ;
     }
 
     //2类通知方法
     protected  void onChange ( boolean selfChange )  {
         synchronized  (mSelfObserverLock )  {
            mContentObservable. dispatchChange (selfChange ) ;
             if  (mNotifyUri  !=  null  && selfChange )  {
                mContentResolver. notifyChange (mNotifyUri, mSelfObserver ) ;
             }
         }
     }
 
     protected  void notifyDataSetChange ( )  {
        mDataSetObservable. notifyChanged ( ) ;
     }
}

再看看Observable类和DataSetObservable类:

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
public  abstract  class Observable <T >  {
     /**
     * 观察者列表
     */

     protected  final ArrayList <T > mObservers  =  new ArrayList <T > ( ) ;
 
     public  void registerObserver (T observer )  {
         if  (observer  ==  null )  {
             throw  new  IllegalArgumentException ( "The observer is null." ) ;
         }
         synchronized (mObservers )  {
             if  (mObservers. contains (observer ) )  {
                 throw  new  IllegalStateException ( "Observer "  + observer  +  " is already registered." ) ;
             }
            mObservers. add (observer ) ;
         }
     }
 
 
     public  void unregisterObserver (T observer )  {
         if  (observer  ==  null )  {
             throw  new  IllegalArgumentException ( "The observer is null." ) ;
         }
         synchronized (mObservers )  {
             int index  = mObservers. indexOf (observer ) ;
             if  (index  ==  - 1 )  {
                 throw  new  IllegalStateException ( "Observer "  + observer  +  " was not registered." ) ;
             }
            mObservers. remove (index ) ;
         }
     }
     
     public  void unregisterAll ( )  {
         synchronized (mObservers )  {
            mObservers. clear ( ) ;
         }        
     }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
public  class DataSetObservable  extends Observable <DataSetObserver >  {
     /**
     * 数据发生变化时,通知所有的观察者
     */

     public  void notifyChanged ( )  {
         synchronized (mObservers )  {
             for  (DataSetObserver observer  : mObservers )  {
                observer. onChanged ( ) ;
             }
         }
     }
     //... ... (其他方法)
}

 观察者DataSetObserver类是一个抽象类:

1
2
3
4
5
public abstract class DataSetObserver {
    public void onChanged() {
        // Do nothing
    }
}

 所以我们具体看它的子类:

1
2
3
4
5
6
7
8
9
10
11
public  class AlphabetIndexer  extends DataSetObserver {
     /*
     * @hide 被android系统隐藏起来了
     */

    @Override
     public  void onChanged ( )  {
         //观察到数据变化,观察者做自己该做的事情
         super. onChanged ( ) ;
        mAlphaMap. clear ( ) ;
     }
}

 ContentObserver也是类似。

4.效果

  • 行为型模式
  • 目标和观察者间的抽象耦合(经典实现)。
  • 支持广播通信(相信这点android开发者看到后应该有启发吧)。
  • 注意意外的更新,这也是观察者更新进行管理的原因之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值