设计模式(二)—— 观察者模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gududedabai/article/details/81077656

由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出与留言。

一、观察者模式原理

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

想要完整代码可以留下邮箱,我会及时发送。

猜你喜欢

转载自blog.csdn.net/gududedabai/article/details/81077656