由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出与留言。
一、观察者模式原理
1、Internet气象站项目,普通OO设计方案,有些问题(扩展不是很好)
案例:
1.1、Internet气象站项目:
设计: 提供温度、气压和湿度的接口
测量数据更新时需时时通知给第三方
需要设计开放型API,便于其他第三方公司也能接入气象站获取数据
1.2、WeatherData类
1.1.1、一个通常的设计方案
设计一个公告板类 (后面优化成接口 放入WeatherData类中)
普通OO设计方案代码如下:
公告板类:
package com.java.hexter.internetweather;
public class CurrentConditions {
private float mTemperature;
private float mPressure;
private float mHumidity;
public void update(float mTemperature,float mPressure,float mHumidity)
{
this.mTemperature=mTemperature;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
display();
}
public void display()
{
System.out.println("***Today mTemperature: "+mTemperature+"***");
System.out.println("***Today mPressure: "+mPressure+"***");
System.out.println("***Today mHumidity: "+mHumidity+"***");
}
}
气象站类:
package com.java.hexter.internetweather;
public class WeatherData {
private float mTemperatrue;
private float mPressure;
private float mHumidity;
private CurrentConditions mCurrentConditions;
public WeatherData(CurrentConditions mCurrentConditions)
{
this. mCurrentConditions= mCurrentConditions;
}
public float getTemperature()
{
return mTemperatrue;
}
public float getPressure()
{
return mPressure;
}
public float getHumidity()
{
return mHumidity;
}
public void dataChange()
{
mCurrentConditions.update(getTemperature(), getPressure(), getHumidity());
}
public void setData(float mTemperature,float mPressure,float mHumidity)
{
this.mTemperatrue=mTemperature;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
}
测试类:
package com.java.hexter.internetweather;
public class InternetWeather {
public static void main(String[] args) {
CurrentConditions mCurrentConditions;
WeatherData mWeatherData;
mCurrentConditions=new CurrentConditions();
mWeatherData=new WeatherData(mCurrentConditions);
mWeatherData.setData(30, 150, 40);
}
}
1.1.2、有些问题
1)其他第三方公司接入气象站获取数据的问题
2)无法在运行时动态的添加第三方 扩展性很差
2、引入观察者模式概念 (通过方法论思考:通过变化的和不变化的部分,把变化的抽离出来)
2.1、观察者模式就像定牛奶业务(其实就是用户在奶站那里订阅牛奶,首先需要先登记在奶站,然后用户就可以通过电话等方式告诉奶站订阅不同牛奶,或者告诉奶站不再订阅。当然奶站有新品种也会通知用户,这就是上面的公告板。)举例如下:
1)奶站,Subject
2)用户,Observer
2.2、Subject:登记注册、移除和通知
2.3、Observer:接收输入
注意:就是通知时候有两种方式:直接通知给Observer和观察者Observer自己去拉数据;细节使用根据参数大小等等业务问题来取用。
2.4、观察者模式: 对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对 象为Observer,Subject通知Observer变化
3、新的设计方案
3.1、用观察者模式设计重新设计的方案
被依赖的对象为Subject,依赖的对 象为Observer,Subject通知Observer变化
这里的Subject相当于之前的WeatherData(气象站)这里定义WeatherDataSt作为区别
这个WeatherDataSt原来的而功能不变,在此基础添加了注册Observer和溢出Observer等功能。
这个Subject接口其实就是用于第三方公司等的一些用户注册,移除,通知等操作。Observer设计成一个观察者接口,这个接口实例化后,其实是一些,公告板,要接入的一些第三方公司等等,就是外面要接入,要实现这个接口。然后观察者通过气象站需要数据时,可以注册,移除等等只要实现update就行。当气象站有数据时,改变数据时候,就会调用通过dataChange()方法,然通过调用通知方法,去通知注册的用户,直接通知数据或者用户去取数据。下面这个案例是采用气象站有数据变化时,去通知观察者模式。
其中WeatherDataSt实现Subject接口,公告板CurrentConditions实现Observer接口,所以各种公告板相当于观察者Observer,以此类推。
代码如下:
Subject:
package com.java.hexter.internetweather.observer;
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
package com.java.hexter.internetweather.mode;
import java.util.ArrayList;
import com.java.hexter.internetweather.observer.Observer;
import com.java.hexter.internetweather.observer.Subject;
public class WeatherDataSt implements Subject{
private float mTemperatrue;
private float mPressure;
private float mHumidity;
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());
}
}
}
Observer:
package com.java.hexter.internetweather.observer;
public interface Observer {
public void update(float mTemperatrue,float mPressure,float mHumidity);
}
各种公告板实现:
ForcastConditions公告板
package com.java.hexter.internetweather.mode;
import com.java.hexter.internetweather.observer.Observer;
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())+"**");
}
}
CurrentConditions公告板
package com.java.hexter.internetweather.mode;
import com.java.hexter.internetweather.observer.Observer;
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 + "***");
}
}
测试代码:
package com.java.hexter.internetweather.mode;
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);
}
}
二、Java内置观察者(原理就是观察者原理,注意是:Observer是个类,注册等方法已经实现了,有好处也有不好的地方)
1、Java内置的观察者
Observable 是个类 注册等方法已经实现比较方便, 但是不能做到多重继承,同时通知时一定要先执行setChange().不执行,通知是不起作用的。
Observer 上面是个接口
2、用Java内置观察者重新设计该项目
3、内置观察者的注意点 Observable是类而不是接口
注意点:(1)、Java内置的观察者实现了拉和推数据。(2)、在通知前一定要setChange,提高了灵活性。(3)、Observer设置成类的好处不用在去实现,但没法定制化,和主动实现注册等功能比较麻烦,Observer等类不能实现多种继承等等。
三、观察者模式关键点
1、示例项目中问题分析
2、观察者模式的意义
3、松耦合、高内聚、隔离影响的意义
4、使用Java内置观察者的注意点
详细学习代码案例包块 内置观察者模式代码:https://download.csdn.net/download/gududedabai/10620878
想要完整代码可以留下邮箱,我会及时发送。