频道栏目
首页 > 程序开发 > 软件开发 > 其他 > 正文
设计模式(二):观察者模式
2016-07-18 10:01:52           
收藏   我要投稿

一、概述

  观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。观察者模式有时成为发布/订阅模式,就是让多个对象在一个对象的状态改变时被通知到。

二、解决问题

  当一个系统有多个类协同工作,如果在一个类中需要知道另外一个类的实现细节才能让系统运转,就会导致系统耦合过紧,以后相互依赖的类改变了或者新增了依赖的类,很多类需要同时更改。为了让交互对象之间能够松耦合,我们可以使用观察者模式。

三、结构类图

\

 

四、成员角色

  抽象主题(Subject):把所有对观察者对象的引用保存到一个集合中,每个抽象主题角色都有任何数量的观察者。抽象主题角色提供一个接口,可以增加和删除观察者。一般用一个抽象类和接口实现。

  抽象观察者(Observer):为所有具体观察者定义一个接口,在得到主题的通知时更新自己。

  具体主题(ConcreteSubject):继承抽象主题,在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  具体观察者(ConcreteObserver):实现抽象观察者所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者可以保存一个指向具体主题的引用。

五、应用实例

  下面是银行账号资金变动下发通知的例子,只要账号资金变动,就会同时下发app客户端消息、邮件消息、短信消息通知客户账号资金变动了

  //主题接口

public interface Subject {
	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObservers();
}

  //抽象主题

abstract public class AbstractSubject implements Subject{
	//可以在这里新增Subject没有的方法,以便子类共用
}

  //观察者接口

public interface Observer {
	public void update(double money);
}

  //app客户端观察者

public class APPObserver implements Observer{
	public void update(double money){
		//发送app客户端通知账号资金变动
		System.out.println("app客户端提醒:您的账户资金变动:" + money);
	}
}

  //邮件观察者

public class MailObserver implements Observer{
	public void update(double money){
		//发送邮件通知账号资金变动
		System.out.println("邮件提醒:您的账户资金变动:" + money);
	}
}

  //短信观察者

public class SmsObserver implements Observer{
	public void update(double money){
		//发送短信通知账号资金变动
		System.out.println("短信提醒:您的账户资金变动:" + money);
	}
}

  //客户银行账号主题

public class AccountSubject extends AbstractSubject{
	//观察者集合
	private List observers;
	//资金变动
	private double money;
	
	public AccountSubject(){
		//主题实例化时,初始化观察者集合
		observers = new ArrayList();
	}
	
	//账号资金变动时通知观察者
	public void notifyObservers() {
		if(observers.size() > 0){
			for(Observer observer:observers){
				observer.update(money);
			}
		}
		
	}

	//注册观察者
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	//删除观察者
	public void removeObserver(Observer o) {
		int i = observers.indexOf(o);
		if(i > 0){
			observers.remove(i);
		}
		
	}
	
	//改变账户资金
	public void changeAccount(double money){		
		System.out.println("账户资金变动:" + money);
		this.money = money;
		
		//通知观察者
		notifyObservers();
	}

}

  //测试观察者

public class TestObserver {
	public static void main(String[] args){
		//创建账号主题
		AccountSubject subject = new AccountSubject();
		
		//创建观察者
		Observer appObserver = new APPObserver();
		Observer smsObserver = new SmsObserver();
		Observer mailObserver = new MailObserver();
		
		//注册观察者到账号主题
		subject.registerObserver(appObserver);
		subject.registerObserver(mailObserver);
		subject.registerObserver(smsObserver);	
		
		subject.changeAccount(7.8);
	}
}

  

测试结果:

\

其实 Java内置了观察者模式,我们可以直接使用java.util包中的Obserber接口和Observable类实现观察者模式。下面我们把上面的代码稍微修改,用Java内置的观察者模式实现银行账号资金变动下发各种通知。

  //首先我们创建被观察者

import java.util.Observable;

public class AccountSubject extends Observable{
	
	//资金变动数额
	private double money;
	
	public AccountSubject(){
	}
	
	//改变账户资金
	public void changeAccount(double money){		
		System.out.println("(测试java自带观察者模式)账户资金变动:" + money);
		this.money = money;
		
		//被观察者状态改变
		this.setChanged(); 
		//java内部实现推拉通知,使用时直接调用notifyObservers(),
		//或者notifyObservers(Object o),传递的参数会在观察者类接收到
		notifyObservers();
	}

	public double getMoney() {
		return money;
	}

	public void setMoney(double money) {
		this.money = money;
	}	

}

  //app客户端观察者

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

public class APPObserver implements Observer{
	//在观察者类图中我们看到,观察者可以持用被观察者的引用
	Observable observale;
	
	public APPObserver(Observable observable){
		this.observale = observable;
		//直接调用java自带的方法,把观察者注册到被观察者
		observable.addObserver(this);
	}

	//具体观察者实现Observer接口的方法,
	//arg1参数就是被观察者的notifyObservers(Object o)传过来的参数
	public void update(Observable arg0, Object arg1) {
		if(arg0 instanceof AccountSubject){
			AccountSubject accountSubject = (AccountSubject)arg0;
			//发送app客户端通知账号资金变动
			System.out.println("app客户端提醒:您的账户资金变动:" + accountSubject.getMoney());
		}
		
	}
}

  //邮件观察者

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

public class MailObserver implements Observer{
	
	//在观察者类图中我们看到,观察者可以持用被观察者的引用
	Observable observale;
	
	public MailObserver(Observable observable){
		this.observale = observable;
		//直接调用java自带的方法,把观察者注册到被观察者
		observable.addObserver(this);
	}
	
	//java的观察者有自带的update方法
	public void update(Observable arg0, Object arg1) {
		if(arg0 instanceof AccountSubject){
			AccountSubject accountSubject = (AccountSubject)arg0;
			//发送app客户端通知账号资金变动
			System.out.println("邮件提醒:您的账户资金变动:" + + accountSubject.getMoney());
		}
	}

}

  //短信观察者

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

public class SmsObserver implements Observer{
	
	//在观察者类图中我们看到,观察者可以持用被观察者的引用
	Observable observale;
	
	public SmsObserver(Observable observable){
		this.observale = observable;
		//直接调用java自带的方法,把观察者注册到被观察者
		observable.addObserver(this);
	}

	//java的观察者有自带的update方法
	public void update(Observable arg0, Object arg1) {
		if(arg0 instanceof AccountSubject){
			AccountSubject accountSubject = (AccountSubject)arg0;
			//发送app客户端通知账号资金变动
			System.out.println("短信提醒:您的账户资金变动:" + + accountSubject.getMoney());	
		}			
	}
}

  //测试java自带观察者模式

import java.util.Observer;

public class TestObserver {
	public static void main(String[] args){
		//创建被观察者,也就是账号主题
		AccountSubject observble = new AccountSubject();
				
		//创建观察者
		Observer appObserver = new APPObserver(observble);
		Observer smsObserver = new SmsObserver(observble);
		Observer mailObserver = new MailObserver(observble);
		
		//账号资金变动
		observble.changeAccount(7.8);
	}
}

  测试结果:

\

六、优点与缺点

  1.优点

  (1)、观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖抽象,而不是依赖具体。从而使各自的变化都不会影响到另一方。主题并不知道任何一个具体的观察者,只知道他们有一个共同的接口。

  (2)、观察者模式支持“广播通信”。主题会向所有的观察者发出通知。

  (3)、观察者模式符合“对修改关闭,对扩展开放”的设计原则。

  2.缺点

  (1)、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会话费很多时间。

  (2)、观察者只知道被观察者发生了变化,但并不知道被观察者是如何发生变化的。

七、使用场景

  1、一个抽象模型有两个方面,其中一个方面依赖另一个方面。将这些方面封装在独立的对象中使它们可以各自独立的改变和复用。

  2、一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少个对象将发生改变,可以降低对象之间的耦合度。

  3、一个对象必须通知其他对象,但而不知道这些对象是谁。就是对象之间的松耦合

八、总结

  1、观察者模式定义了对象之间一对多关系。

  2、有多个观察者时,不可以依赖特定的通知次序。

  3、java有通用的观察者模式(java.util.Observable)。

  4、观察者与被观察者之间用松耦合方式结合。

  5、简单理解就是一个对象状态的改变要通知到其它对象。

 

点击复制链接 与好友分享!回本站首页
上一篇:关于面向对象
下一篇:Reactor 模式的简单实现
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站