设计模式之观察者模式
1. 什么是观察者模式
Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。
-
Subject(被观察者)
被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。 -
ConcreteSubject
被观察者的具体实现。包含一些基本的属性状态及其他操作。 -
Observer(观察者)
接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。 -
ConcreteObserver
观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。
2. 具体实例
首先我有一个Internet的气象站项目:
提供温度、气压和湿度的接口
测量数据更新时需时时通知给第三方
需要设计开放型API,便于其他第三方公司也能接入气象站获取数据
我首先按照面向对象的设计过程,我首先想到的是设计两个类,一个是天气的数据,一个就是公告板也就是对天气的数据进行操作的类
具体实现如下:
CurrentConditions:
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+"***");
}
}
WeatherData:
public class WeatherData {
private float mTemperature;
private float mPressure;
private float mHumidity;
private CurrentConditions currentConditions;
public WeatherData( CurrentConditions currentConditions){
this.currentConditions = currentConditions;
}
public float getmTemperature() {
return mTemperature;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidity() {
return mHumidity;
}
public void dataChange(){
currentConditions.update( getmTemperature(),getmPressure(),getmHumidity());
}
public void setData(float mTemperature,float mPressure,float mHumidity)
{
this.mTemperature=mTemperature;
this.mPressure=mPressure;
this.mHumidity=mHumidity;
dataChange();
}
}
这样设计带来的问题是什么呢?
1)其他第三方公司接入气象站获取数据的问题
2)无法在运行时动态的添加第三方
也就是说我们想要再添加新的公告板的时候,同时需要更改WeatherData类,这样的话工作量变大,不符合设计要求。
根据上面观察者模式,我们重新设计我们的方案,也就是留出subject和observer两个接口,由WeatherDada和CurrentConditions分别继承实现,这样的话我再来新的公告板的话只需要扩展observer这个接口就可以了。
observer接口:
public interface Observer {
public void update(float mTemperatrue,float mPressure,float mHumidity);
}
subject接口:
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
WeatherDataSt继承自subject,然后observer由ArrayList组成,这样的话每扩展一个公告板就只需要注册Observer就可以了。
public class WeatherDataSt implements Subject {
private float mTemperature;
private float mPressure;
private float mHumidityp;
ArrayList<Observer> observers;
public float getmTemperature() {
return mTemperature;
}
public float getmPressure() {
return mPressure;
}
public float getmHumidityp() {
return mHumidityp;
}
public WeatherDataSt(){
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if (observers.contains(o)){
observers.remove(o);
}
}
@Override
public void notifyObservers() {
for (int i = 0; i < observers.size(); i++){
observers.get(i).update(getmTemperature(),getmPressure(),getmHumidityp());
}
}
public void dataChange(){
notifyObservers();
}
public void setData(float mTemperature,float mPressure,float mHumidity){
this.mTemperature = mTemperature;
this.mPressure = mPressure;
this.mHumidityp = mHumidity;
dataChange();
}
}
公告板
public class ConcurrentConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidityp;
@Override
public void update(float mTemperature, float mPressure, float mHumidity) {
this.mTemperature =mTemperature;
this.mPressure = mPressure;
this.mHumidityp = mHumidity;
display();
}
public void display(){
System.out.println("***Today mTemperatrue:" + mTemperature + "***");
System.out.println("***Today mPressure:" + mPressure + "***");
System.out.println("***Today mHumidity:" + mHumidityp + "***");
}
}
这个时候我想要添加一个气象预报的公告板,只需要继承Observer接口然后在WeatherData中注册就可以了
public class ForcastConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidityp;
@Override
public void update(float mTemperature, float mPressure, float mHumidity) {
this.mTemperature = mTemperature;
this.mPressure = mPressure;
this.mHumidityp = mHumidity;
displsy();
}
public void displsy(){
System.out.println("**明天温度:"+(mTemperature+Math.random())+"**");
System.out.println("**明天气压:"+(mPressure+10*Math.random())+"**");
System.out.println("**明天湿度:"+(mHumidityp+Math.random())+"**");
}
}
public class InternetWeatherOb {
public static void main(String[] args){
ConcurrentConditions concurrentConditions = new ConcurrentConditions();
WeatherDataSt weatherDataSt = new WeatherDataSt();
weatherDataSt.registerObserver(concurrentConditions);
weatherDataSt.setData(10,200,20);
ForcastConditions forcastConditions = new ForcastConditions();
weatherDataSt.registerObserver(forcastConditions);
weatherDataSt.setData(20,300,30);
}
}
通过上面的例子我们可以看出通过观察者模式,我们可以轻松的扩展程序,扩展后只需要让观察者通知被观察者发生的改变即可。
3. java内置的观察者模式
Java内置的观察者:
- Observable
- Observer
接下来通过内置的观察者模式来上面的例子
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(); //boolean类型的,是否发生了改变
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 ConcurrentConditions implements Observer {
private float mTemperature;
private float mPressure;
private float mHumidityp;
@Override
public void update(Observable o, Object arg) {
this.mTemperature = ((WeatherData.Data) arg).mTemperatrue;
this.mPressure = ((WeatherData.Data) arg).mPressure;
this.mHumidityp = ((WeatherData.Data) arg).mHumidity;
display();
}
public void display()
{
System.out.println("***Today mTemperatrue:" +mTemperature+"***");
System.out.println("***Today mPressure:" +mPressure+"***");
System.out.println("***Today mHumidity:" +mHumidityp+"***");
}
}
public class InternetWeather {
public static void main(String[] args){
ConcurrentConditions concurrentConditions = new ConcurrentConditions();
WeatherData weatherData = new WeatherData();
weatherData.addObserver(concurrentConditions); //添加
weatherData.setData(10,100,10);
}
}
其实就是通过继承Java内部的Observable和Observer,实现观察者模式,不用自己去写这俩个接口了。
4. 典型应用
Observer模式的典型应用:
-
侦听事件驱动程序设计中的外部事件
-
侦听/监视某个对象的状态变化
-
发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者