《Java设计模式之观察者模式》

《观察者模式》

  观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
  观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。当这个主题对象的状态发生变化时,就会通知所有的观察者,使他们更新自己。

  1.观察者模式的结构

        抽象主题角色(Subject):抽象主题将所有的观察者保存在一个集合中,并定义了增加、删除、通知三个方法。
        具体主题角色(ConcreteSubject):当自己的状态发生变化时,就会通知所有登记过的观察者。
        抽象观察者角色(Observer):定义了一个更新的方法,让具体主题对象在通知时会调用该方法。
        具体观察者角色(ConcreteObserver):存储和主体相同的状态,当被通知时,具体的update方法被调用,状态得以更新。

  2.自定义观察者模式实现HeadFirst设计模式中的气象站的例子:

//通知者接口(Subject)
public interface Subject {
	//添加观察者
	void addObserver(Observer obj);
	//移除观察者
	void removeObserver(Observer obj);
	//通知观察者
	void notifyObservers();
}
//主题类(ConcreteSubject)
public class WeatherData implements Subject {
	private List<Observer> list;
	private float temp;
	private float humidity;
	private float pressure;
	//初始化集合
	public WeatherData() {
		list = new ArrayList<Observer>();
	}
	//添加观察者
	@Override
	public void addObserver(Observer obj) {
		list.add(obj);
	}
	//移除观察者
	@Override
	public void removeObserver(Observer obj) {
		list.remove(list.indexOf(obj));
	}
	//通知所有观察者,会调用所有观察者的update()
	@Override
	public void notifyObservers() {
		for (Observer obj : list) {
			obj.update(temp, humidity, pressure);
		}
	}
	//一旦气象站监测的数据发生变化,就会调用该方法
	public void mesureChanged(){
		notifyObservers();
	}
	//该方法用来模拟监测数据变化,会调用mesureChanged方法
	public void setMeasurements(float temp,float humidity,float pressure){
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		mesureChanged();
	}
}
//抽象观察者(Observer)
public interface Observer {
	void update(float temp,float humidity,float pressure);
}
//展示的公告(ConcreteObserver)
public class CurrentConditionsDisplay implements Observer{
	private float temp;
	private float humidity;
	private float pressure;
	//直接在构造函数中完成观察者的添加
	public CurrentConditionsDisplay(Subject subject) {
		subject.addObserver(this);
	}
	//展示数据
	public void display() {
		System.out.println("温度为"+temp);
		System.out.println("湿度为"+humidity);
		System.out.println("压力为"+pressure);
	}
	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		display();
	}
}
//测试
public class TestObserver {
	@Test
	public void testObserver(){
		//创建通知者
		WeatherData wd = new WeatherData();
		//创建观察者
		CurrentConditionsDisplay ccd = new CurrentConditionsDisplay(wd);
		//模拟测试温度变化
		wd.setMeasurements(20, 1l, 22);
	}
}

  3.观察者模式中的推模型和拉模型

        推模型:就像上面的示例,如果气象站监测的数据发生变化,它会把所有的数据全部发送给观察者, 不管该观察者是否需要所有的数据。
        拉模型:主题在通知观察者时,一般会将自身对象通过update()方法传递过去,然后自身提供数据的getter方法,让观察者通过自身需要通过getter()方法获取想要的数据。

  通过Java.util.Observable类和Java.util.Observer接口可以Java内置的观察者模式,我们通过Java内置的观察者模式将上面的示例改造成拉模型:
//继承Jdk内置通知者
public class WeatherData extends Observable {
	private float temp;
	private float humidity;
	private float pressure;
	
	//一旦气象站监测的数据发生变化,就会调用该方法
	public void mesureChanged(){
		//调用通知方法前,必须调用setChanged()
		setChanged();
		notifyObservers();
	}
	//该方法用来模拟监测数据变化,会调用mesureChanged方法
	public void setMeasurements(float temp,float humidity,float pressure){
		this.temp = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		mesureChanged();
	}
	//听过getter方法供观察者获取数据
	public float getTemp() {
		return temp;
	}
	public float getHumidity() {
		return humidity;
	}
	public float getPressure() {
		return pressure;
	}
}
//实现Java内置的Observer接口
public class CurrentConditionsDisplay implements Observer {
	private Observable obs;
	private float temp;
	private float humidity;
	private float pressure;
	//传入通知者,用于添加观察者
	public CurrentConditionsDisplay(Observable obs) {
		obs.addObserver(this);
		this.obs = obs;
	}
	@Override
	public void update(Observable obs, Object obj) {
		if (obs instanceof WeatherData){
			//通过getter方法来获取数据
			WeatherData wd = (WeatherData) obs;
			this.temp = wd.getTemp();
			this.humidity = wd.getHumidity();
			this.pressure = wd.getPressure();
		}
		display();
	}
	
	public void display(){
		System.out.println("温度为"+temp);
		System.out.println("湿度为"+humidity);
		System.out.println("压力为"+pressure);
	}
}
//测试
public class TestObserver {
	@Test
	public void testObserver(){
		//创建主题
		WeatherData wd = new WeatherData();
		//创建观察者
		CurrentConditionsDisplay ccd = new CurrentConditionsDisplay(wd);
		//更新主题数据
		wd.setMeasurements(10, 12, 13);
	}
}
  尽管Java为我们提供了内置的观察者模式,但是其中也有不足之处。我们发现 Observable是一个类而不是接口,所以我们要实现观察者模式就必须继承它,而由于Java并不支持多继承,所以我们的主题类就没办法继承别的类。而且由于Observable的setChanged方法被protected修饰,导致我们没法通过组合的方式调用该方法,这也违法了Java的设计原则“多组合,少继承"。

  4.推模型和拉模型的区别  

           1)推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。

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


  5.总结

     优点:
       1.Java中有很多地方都是用了观察者模式,比如Swing、RMI等,观察者模式在被观察者和观察者之间建立了一种抽象的耦合,即被观察者并不知道观察者具体的实现,只知道它们都实现了同一个就,这样可以很好的实现程序见的松耦合。
     缺点:
       1.如果使用Java内置的观察者模式,应该注意它存在的一些问题,比如在有多个观察者时,不要依赖特定的通知顺序,Observable是个类且没有实现任何借口,导致扩展性不好。
       2.如果被观察者有过多的直接观察者或间接观察者,这就会导致每一次通知的耗时过长。
 
           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值