码迷,mamicode.com
首页 > 其他好文 > 详细

观察者模式

时间:2018-04-16 14:34:10      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:script   str   观察者   ram   目的   turn   gre   消息通知   两种   

最近看了<Head First设计模式>里的观察者模式,代码逻辑并没有什么太花哨的东西,但是对于代码结构设计可扩展性有一定的启发.下面是书中内容的简单整理:

业务需求:

设计一个气象监测应用,在温度,气压,湿度变化时在公告板显示数据;

需求分析:
目的用于数据显示,所以可以将代码分为三块:监控设备,气象站数据,公告板
业务流程:监控设备获取原始信息->气象站获取原始信息->通知公告板信息变更显示

核心业务逻辑:

气象站代码实现:
public class WeatherData {
  // 更新公告板数据
  public void measurementsChanged() {
    // 获取最新温度,气压,湿度数据
    float temp = getTemperature();
    float humidity = getHumidity();
    float pressure = getPressure();

    // 更新公告板信息
    currentConditionsDisplay.update(temp,humidity,pressure);
  }
}

其实实现功能就是当监控设备的数据变化时,调取公告板更新显示数据;

但是这个代码有一些问题:
  针对具体实现编程,未针对接口编程,代码耦合性高,可扩展性较差;

所以这里可以用观察者模式进行规范,降低耦合性,增加扩展性;
观察者模式:定义对象间一对多依赖,当一个对象状态变化时,它的所有依赖着都会收到通知并自动更新;
类似于消息订阅,观察者统一在主题处注册,当有新消息时主题通知观察者,完成数据触发操作;
消息获取存在推,拉两种消息获取方式:
  推:消息获取直接,但是信息量大,扩展时就要修改接口;
  拉:消息获取较复杂,但是扩展方便;

观察者模式设计:

定义三个接口:Subject(主题),Observer(观察者),DisplayElement(显示元素);

定义具体实现类:WeatherData(气象数据)实现Subject接口;公告板实现Observer,DisplayElement接口;

代码实现:

主题接口:

// 管理接收信息的观察者,进行消息通知
public interface Subject {
  void registerObserver(Observer observer);
  void removeObserver(Observer observer);
  // 激活观察者状态更新
  void notifyObservers();
}

观察者接口:

// 观察者,进行消息更新
public interface Observer {
  /**
  * @Description: 更新观察者数据
  * @param subject:主题
  * @param obj:推送消息
  */
  void update(Subject subject,Object obj);
}

数据显示接口:

public interface DisplayElement {
	void display();
}

主题具体实现类:

public class WeatherData implements Subject {
	private List<Observer> observers;
	private float temp;
	private float humidity;
	private float pressure;
	private boolean changed;// 更新标识

	public WeatherData() {
		// 实例初始化再创建对象,缩短生命周期,减少资源占用
		observers = new ArrayList<>();
	}

	@Override
	public void registerObserver(Observer observer) {
		observers.add(observer);
	}

	@Override
	public void removeObserver(Observer observer) {
		observers.remove(observer);
	}

	public void notifyObservers(Object org) {
		if (changed) {
			for (Observer observer : observers) {
				observer.update(this, org);
			}
			changed = false;
		}
	}

	@Override
	public void notifyObservers() {
		notifyObservers(null);
	}

	// 自身的更新方法
	public void measurementsChanged() {
		setChanged();
		notifyObservers();
	}

	public void setMeasurements(float temp, float humidity, float pressure) {
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}

	// 设置更新标识,控制更新频率和状态
	private void setChanged() {
		changed = true;
	}

	public float getTemp() {
		return temp;
	}

	public float getHumidity() {
		return humidity;
	}

	public float getPressure() {
		return pressure;
	}
	
}

公告板具体实现类:

public class CurrentConditionDisplay implements Observer,DisplayElement{
	private float temp;
	private float humidity;
	private Subject subject;

	// 接收主题的消息激活
	public CurrentConditionDisplay(Subject subject) {
		this.subject=subject;
		subject.registerObserver(this);
	}

	/**
	 * @Description: 更新信息
	 * @param subject:消息源主题
	 * @param obj:接收参数
	 */
	@Override
	public void update(Subject subject,Object obj) {
		if(subject instanceof WeatherData) {
			WeatherData WeatherData = (WeatherData)subject;
			this.temp=WeatherData.getTemp();
			this.humidity=WeatherData.getHumidity();
			display();
		}
	}
	@Override
	public void display() {
		System.out.println("Current conditions: "+temp+" F degrees and "+humidity+"% humidity");
	}

	public void cancelRegister() {
		subject.removeObserver(this);
	}
}

因为公共接口的抽取,让整体的代码层次更清晰,简单;降低了代码间的耦合度,这也让未来代码扩展更方便;

观察者模式

标签:script   str   观察者   ram   目的   turn   gre   消息通知   两种   

原文地址:https://www.cnblogs.com/chengmuyu/p/8855446.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!