观察者模式

本文从以下方法阐述观察者模式

一、定义观察者

二、观察者模式示例

三、推模型与拉模型

四、JAVA内置观察者

五、总结

 

一、定义观察者模式

 

 1、定义

       观察者模式为对象的行为模式,主要定义一种一对多的对象关系(观察者:主题对象=1:n)。让多个观察者对象去监听同一个主题对象Subject(被依赖的对象),当主题对象的内容状态发生变化时,会通知所有注册过的观察者对象,促使观察者对象的内容更新。

 

2、观察者模式的结构图

(1)以订报纸业务为例:

          报社:Subject(主题类,被依赖的对象)

          订阅者:Observer 观察者(依赖报社)

(2)报社Subject:负责,登记注册,通知,移除观察者的工作

(3)订阅者Observer:负责接收报社通知拿报纸



 

二、观察者模式示例

 

1、主题类接口

 

package net.oschina.design.observer.interfac;

/**
 * 观察者模式中的主类,被依赖的类
 * 
 * @author Freedom
 * 
 */
public interface Subject {
	/*
	 * 注册观察者
	 */
	public void registObserver(Observer o);

	// 移除观察者
	public void removeObserver(Observer o);

	// 通知观察者
	public void notifyObserver();
}
 

 

2、观察者接口

 

package net.oschina.design.observer.interfac;

/**
 * 观察者模式中 依赖的类
 * 
 * @author Freedom
 * 
 */
public interface Observer {

	/*
	 * 实时更新subject类中的数据
	 */
	public void updateDate(float temp, float press);

}
 

 

3、主题类的实现

 

package net.oschina.design.observer.interfac.impl;

import java.util.ArrayList;
import java.util.List;

import net.oschina.design.observer.interfac.Observer;
import net.oschina.design.observer.interfac.Subject;

/**
 * 气象台主类
 * 
 * @author Freedom
 * 
 */
public class WeatherData implements Subject {

	private final List<Observer> observerList; // 模拟注册保存观察者数据的链表

	private float temp;// 气温

	private float press;// 气压

	public WeatherData() {
		observerList = new ArrayList<Observer>(5);
	}

	@Override
	public void registObserver(Observer o) {
		if (null != o) {
			observerList.add(o);
		}
	}

	@Override
	public void removeObserver(Observer o) {
		if (null != o) {
			observerList.remove(o);
		}
	}

	// 通知观察者
	@Override
	public void notifyObserver() {

		if (null != observerList && !observerList.isEmpty()) {
			for (Observer o : observerList) {
				// 观察者实时显示天气信息
				o.updateDate(this.getTemp(), this.getPress());
			}
		}
	}

	// 设置参数
	public void setWeather(float temp, float press) {
		this.temp = temp;
		this.press = press;

		// 气象台更新了数据后,通知观察者
		this.notifyObserver();
	}

	/*
	 * setter /getter
	 */
	public float getTemp() {
		return temp;
	}

	public void setTemp(float temp) {
		this.temp = temp;
	}

	public float getPress() {
		return press;
	}

	public void setPress(float press) {
		this.press = press;
	}

}
 

 

4、观察者类的实现

 

package net.oschina.design.observer.interfac.impl;

import net.oschina.design.observer.interfac.Observer;

/**
 * 显示当前气温的观察者
 * 
 * @author Freedom
 * 
 */
public class CurrentWeatherObserver implements Observer {

	/*
	 * 观察者实时更新天气(non-Javadoc)
	 * 
	 * @see
	 * net.oschina.design.observer.interfac.Observer#updateDate(net.oschina.
	 * design.observer.interfac.Subject)
	 */
	@Override
	public void updateDate(float temp, float press) {
		this.display(temp, press);
	}

	public void display(float temp, float press) {
		System.out.println("今天天气****气温****" + temp);
		System.out.println("今天天气****气压****" + press);
	}

}

 

5、运行代码

 

package net.oschina.design.observer;

import net.oschina.design.observer.interfac.impl.CurrentWeatherObserver;
import net.oschina.design.observer.interfac.impl.WeatherData;

public class MainObserver {

	public static void main(String[] args) {
		// subject
		WeatherData w = new WeatherData();
		// observer
		CurrentWeatherObserver cur = new CurrentWeatherObserver();

		w.registObserver(cur);
		w.setWeather(11.1f, 213.111111f);

	}

}
 


 

上述代码运行分析:先实例化一个主题类对象,然后实例化一个观察者类的对象,之后主题对象中注册观察者对象。当主类对象中数据改变时,就通知观察者对象,观察者对象获取到主题对象发来的信息后,及时更新自己的信息并显示。

 

三、推模型与拉模型

  在观察者模式中,又分为推模型和拉模型两种方式。

1、推模型

  主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

 

2、拉模型

  主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

 

3、两种模型比较

     (1)推模型是假定主题对象知道观察者需要的数据(个人愚见,主题的主动行为);而拉模型是主题对象不知道观察者具体需要什么数据,直接将主题对象本身传递给观察者(主题的被动行为所需数据要观察者根据需要自己获取),让观察者自己去按需要取值。

     (2)推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。

 

四、JAVA内置观察者

 

1、主题类:继承Observable类

 

package net.oschina.design.observer.innerobserver.subject;

import java.util.Observable;

/**
 * java内置观察者,主类
 * 
 * @author Freedom
 * 
 */
public class WeatherData extends Observable {

	private float temp;// 温度
	private float press;// 气压

	/*
	 * 主类数据变化通知观察者
	 */
	public void change() {
		// 必须要调用setChanged方法
		this.setChanged();
		// 调用通知方法,调用通知方法,拉模型将主题的所有数据传递给观察者
		this.notifyObservers(new Data(this.getTemp(), this.getPress()));
	}

	/**
	 * 设置主类中将要通知给观察者的数据
	 */
	public void setData(float temp, float press) {
		this.temp = temp;
		this.press = press;

		// 调用通知方法
		change();
	}

	public float getTemp() {
		return temp;
	}

	public float getPress() {
		return press;
	}

	/**
	 * 保存主类数据的内置对象
	 * 
	 * @author Freedom
	 * 
	 */
	public class Data {

		private float temp;// 温度
		private float press;// 气压

		public Data(float temp, float press) {
			this.temp = temp;
			this.press = press;
		}

		public Data() {
		}

		public float getTemp() {
			return temp;
		}

		public float getPress() {
			return press;
		}

	}

}
 

 

2、观察者类实现java.util.Observer接口

 

package net.oschina.design.observer.innerobserver.observer;

import java.util.Observable;
import java.util.Observer;

import net.oschina.design.observer.innerobserver.subject.WeatherData.Data;

/**
 * 当前天气的观察者
 * 
 * @author Freedom
 * 
 */
public class CurrentWeather implements Observer {

	private float temp;
	private float press;

	@Override
	public void update(Observable o, Object arg) {
		this.temp = ((Data) (arg)).getTemp();
		this.press = ((Data) (arg)).getPress();

		display();

	}

	// 显示天气
	public void display() {
		System.out.println("当天天气[温度]:" + temp + "  [气压]:" + press);
	}

}
 

 

3、运行类

 

package net.oschina.design.observer.innerobserver.main;

import net.oschina.design.observer.innerobserver.observer.CurrentWeather;
import net.oschina.design.observer.innerobserver.subject.WeatherData;

public class MainInnerObserver {

	public static void main(String[] args) {

		WeatherData w = new WeatherData();
		CurrentWeather c = new CurrentWeather();

		w.addObserver(c);// 注册观察者
		w.setData(11.1f, 22.5f);

	}

}
 

 

 

4、查看源码内置观察者的方法如下



 

5、注意事项:

①主类通知观察者对象之前要调用 setChanged()方法,然后再调用notifyObservers()通知方法;

解释:直接看源码一目了然



 



 

 

四、总结

 

1、观察者模式主要为了解决:对象之间存在1:N依赖关系的情况,被依赖的一方为主题类,依赖的一方为观察者类;

2、观察者模式又叫发布-订阅(Publish/Subscribe)模式模型-视图(Model/View)模式源-监听器(Source/Listener)模式从属者(Dependents)模式;

3、观察者模式,可以有效的降低对象之间的耦合度,比如说:当主题类停止工作时,观察者最多是接受不到数据,依然可以继续工作

4、java内置观察者,主题类为一个实体类Observable类而非接口,调用通知方法前先调用setChanged方法;内置观察者主题类中注册观察者时维护了一个集合为Vector

 

 

如上,内容可能还有遗漏欠缺,还请高端玩家斧正留言.....

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值