观察者模式

一.引子

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化, 例如:1.京东上某个商品暂时没货,提示用户关注后到货通知,这个暂时无货的商品是被观察者,点击关注这个商品的用户就是观察者。 2、老师针对成绩在60分以下的同学定期发送最新的考题分析邮件,每轮考试下来都会有不及格的同学,由不及格变为及格的同学自动从邮件列表里移除,新的不及格的同学会被加进邮件列表里。在这样的情况下就可以使用观察者模式。

 

二、观察者模式

  1. 观察者模式的概念:

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。依赖的对象为Observer,Subject通知Observer变化。

  

  2.模式的结构:

      观察者模式的结构中包含四种角色:

    (1) 主题(subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加,删除观察者以及通知观察者更新数据的方法、

    (2) 观察者(Observer):观察者是一个借口,该接口规定了具体观察者用来更新数据的方法。

    (3) 具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。

    (4) 具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题的主题接口变量,一遍具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己称为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。

 

三.范例

        气象站现在需要我们做一个公告项目,通过感应状态获取的数据将气象状态进行展示。

                                                     

一般的设计方案中,我们在WeatherData对象中,存放他们的引用,然后当我的值变化的时候,依次调用公告板的change() 函数通知变化。但这样的方案却又很多问题:

  1. 没有面相接口编程的思想
  2. 如果还有新的广告板,需要修改WeatherData
  3. 如果通知的信号(温度,湿度,气压)再增加一个参数,那么dataChange需要修改,所有的广告板都需要修改。

                                                                

因此,我们用观察者模式重新设计方案。

                                                     

 

在这个项目中,我们其实可以看作广告板为(观察者Observer),时刻关注着 WeatherData (主题Subject) 的变化,如果有变化,则通知广告板更新。

 

首先提供主题和观察者两个接口:

//主题Subjet接口
public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}
//观察者Observer接口
public interface Observer {
    public void update(float mTemperatrue,float mPressure,float mHumidity);
}

 

 然后创建具体主题WeatherData(ConcreteSubject)和具体观察者广告板(ConcreteObserver)

//具体主题
public class WeatherDataSt implements Subject{
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    //创建Lisr,存放观察者引用
    private ArrayList<Observer> mObservers;
    
    public WeatherDataSt()
    {
        mObservers=new ArrayList<Observer>();
    }
    
    public float getTemperature()
    {
        return mTemperatrue;
        
    }
    
    public float getPressure()
    {
        return mPressure;
        
    }
    
    public float getHumidity()
    {
        return mHumidity;
        
    }
    public void dataChange()
    {
        notifyObservers();
    }

    

    
    
    
    public void setData(float mTemperatrue,float mPressure,float mHumidity)
    {
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }

    @Override
    public void registerObserver(Observer o) {
        // TODO Auto-generated method stub
        mObservers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        // TODO Auto-generated method stub
        if(mObservers.contains(o))
        {mObservers.remove(o);}
    }

    @Override
    public void notifyObservers() {
        // TODO Auto-generated method stub
        for(int i=0,len=mObservers.size();i<len;i++)
        {
            mObservers.get(i).update(getTemperature(), getPressure(), getHumidity());
        }
    }

}
//具体观察者广告板1
public class CurrentConditions implements Observer {

    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;

    @Override
    public void update(float mTemperatrue, float mPressure, float mHumidity) {
        // TODO Auto-generated method stub
        this.mHumidity = mHumidity;
        this.mPressure = mPressure;
        this.mTemperatrue = mTemperatrue;
        display();
    }

    public void display() {
        System.out.println("***Today mTemperatrue:" + mTemperatrue + "***");
        System.out.println("***Today mPressure:" + mPressure + "***");
        System.out.println("***Today mHumidity:" + mHumidity + "***");

    }

}
//观察板2
public class ForcastConditions implements Observer{
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(float mTemperatrue, float mPressure, float mHumidity) {
        // TODO Auto-generated method stub
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        
        display();
    }
    public void display()
    {
        System.out.println("**明天温度:"+(mTemperatrue+Math.random())+"**");
        System.out.println("**明天气压:"+(mPressure+10*Math.random())+"**");
        System.out.println("**明天湿度:"+(mHumidity+Math.random())+"**");
    }
}
//客户端调用,主方法
public class InternetWeather {

    public static void main(String[] args) {
        
        CurrentConditions mCurrentConditions;
        ForcastConditions mForcastConditions;
        WeatherDataSt mWeatherDataSt;
        
        mWeatherDataSt=new WeatherDataSt();
        mCurrentConditions=new CurrentConditions();
        mForcastConditions=new ForcastConditions();
        
        mWeatherDataSt.registerObserver(mCurrentConditions);
        mWeatherDataSt.registerObserver(mForcastConditions);
        
        mWeatherDataSt.setData(30, 150, 40);
        mWeatherDataSt.removeObserver(mCurrentConditions);
        mWeatherDataSt.setData(40, 250, 50);
    }

 这样,我们的观察者模式就完成了,这样做的好处:

  1. 首先现在 WeatherData 可以添加任意多个观察者
  2. 主题和观察者解耦,类中保持的是接口对象。
  3. 观察主题的具体内容解耦了,WeatherData获取的信息,和Observer关心的数据分开。

 四、JAVA中自带的观察者模式

     Java 的 java.util包 中自带了 Observer接口和Observable类和我们前面的 Subject接口和Observer接口很像。

  我们来看看使用Java的观察者模式,重写上面的例子:

public class WeatherData extends Observable{
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    
    public float getTemperature()
    {
        return mTemperatrue;
        
    }
    
    public float getPressure()
    {
        return mPressure;
        
    }
    
    public float getHumidity()
    {
        return mHumidity;
        
    }
    
    
    public void dataChange()
    {
        this.setChanged();
        this.notifyObservers(new Data(getTemperature(),getPressure(),getHumidity()));
        
    }
    
    
    public void setData(float mTemperatrue,float mPressure,float mHumidity)
    {
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }
    
    public class Data
    {
        public float mTemperatrue;
        public float mPressure;
        public float mHumidity;
        public Data(float mTemperatrue,float mPressure,float mHumidity)
        {
            this.mTemperatrue=mTemperatrue;
            this.mPressure=mPressure;
            this.mHumidity=mHumidity;
        }
    }
    
}
public class CurrentConditions implements Observer {
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(Observable arg0, Object arg1) {
        // TODO Auto-generated method stub
        this.mTemperatrue=((Data)(arg1)).mTemperatrue;
        this.mPressure=((Data)(arg1)).mPressure;
        this.mHumidity=((Data)(arg1)).mHumidity;
        display();
    }
    
    public void display()
    {
        System.out.println("***Today mTemperatrue:" +mTemperatrue+"***");
        System.out.println("***Today mPressure:" +mPressure+"***");
        System.out.println("***Today mHumidity:" +mHumidity+"***");
    }
    
    
}

 

posted on 2018-03-27 22:33  朽木藏虫  阅读(196)  评论(0)    收藏  举报