码迷,mamicode.com
首页 > 编程语言 > 详细

Java设计模式之观察者模式

时间:2015-07-23 22:03:56      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

观察者模式是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。这一模式中的关键对象是目标(Subject)和观察者(Obserber)。一个目标可以有任意个观察者,一旦目标状态发生改变,所有的观察者将得到通知。这种交互也称为发布-订阅

观察者模式的适用场景:

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

当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。

当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。

基本结构:

Subject<---------ConcreteSubject

Observer<----------ConcreteObserver

Subject(目标):目标知道它的观察者,可以有任意个观察者;提供attach()、detach()、notifyObservers()方法接口。

ConcreteSubject(具体目标):写入具体目标对象的状态或内容(getter and setter方法),并且在它们的状态发生改变时会向它的观察者发出通知。

Observer(观察者):定义目标发生改变时需获得通知的对象定义一个接口,Update()方法。

?ConcreteObserver(具体观察者):?维护一个指向ConcreteSubject对象的引用;存储观察者自身的状态,实现Observer接口使自身状态与目标状态保持一致。

观察者模式允许独立的改变目标和观察者。可以单独复用目标对象而无需同时复用其观察者,反之亦然。

观察者模式的优点:目标与观察者之间的抽象耦合,耦合与抽象达到最小;支持广播更新。

观察者模式的缺点:容易引起误广播,即其中一个观察者修改了目标的状态,则其他观察者也收到了该更新。

观察者模式的实现需要考虑以下几个关键点:1.创建目标到其观察者之间的映射;2.观察多个目标;3.谁触发更新;4.对已删除目标的悬挂引用;5.在发出通知之前一定要确保目标的状态自身是一致的;6.避免特定于观察者的更新协议——推/拉模型:推模型是指目标向观察者发送关于改变的详细信息,而不管他们需要与否。拉模型是指目标除最小通知外什么也不送出,而此后由观察者显示地向目标询问细节。7.显示地指定感兴趣的改变。即可以让观察者对感兴趣的目标才接受通知。


下面通过一段代码来演示一下观察者模式的应用案例:

Subject.java

package com.observer.classic;

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

/**
 * 观察者模式
 * 目标对象
 * @author zzw
 */
public class Subject {

	//不同兴趣点观察者线性列表
	private List<Observer> observersAll = new ArrayList<Observer>();
	
	private List<Observer> observersMusic = new ArrayList<Observer>();
	
	private List<Observer> observersSport = new ArrayList<Observer>();
	
	private List<Observer> observersMovie = new ArrayList<Observer>();
	
	//增加观察者
	public void attach(Observer observer) {
		String interest = observer.getObserverInterest();
		if("All".equals(interest)) {
			observersAll.add(observer);
		} else if("Music".equals(interest)) {
			observersMusic.add(observer);
		} else if("Sport".equals(interest)) {
			observersSport.add(observer);
		} else if("Movie".equals(interest)) {
			observersMovie.add(observer);
		}
	}
	
	//删除观察者
	public void detach(Observer observer) {
		String interest = observer.getObserverInterest();
		if("All".equals(interest)) {
			observersAll.remove(observer);
		} else if("Music".equals(interest)) {
			observersMusic.remove(observer);
		} else if("Sport".equals(interest)) {
			observersSport.remove(observer);
		} else if("Movie".equals(interest)) {
			observersMovie.remove(observer);
		}
	}
	
	
	public void notifyObservers(String subjectTag) {
		if("Music".equals(subjectTag)) {
			for(Observer observer : observersMusic) {
				observer.update(this);
			}
		} else if("Sport".equals(subjectTag)) {
			for(Observer observer : observersSport) {
				observer.update(this);
			}
		} else if("Movie".equals(subjectTag)) {
			for(Observer observer : observersMovie) {
				observer.update(this);
			}
		}
		
		for(Observer observer : observersAll) {
			observer.update(this);
		}
	}
}


Observer.java

package com.observer.classic;
/**
 * 观察者接口
 * @author zzw
 *
 */
public interface Observer {

	public void update(Subject subject);
	
	public String getObserverInterest();
}

ConcreteSubject.java

package com.observer.classic;
/**
 * 具体的目标对象
 * 负责把目标的状态信息存入到相应的观察者身上
 * @author zzw
 */
public class ConcreteSubject extends Subject {

	//相应目标的状态(内容)
	private String subjectState;
	
	//目标通知的分类标签
	private String subjectTag;
	
	public String getSubjectTag() {
		return subjectTag;
	}


	public String getSubjectState() {
		return subjectState;
	}

	public void setSubjectState(String subjectState,String subjectTag) {
		this.subjectState = subjectState;
		this.subjectTag = subjectTag;
		this.notifyObservers(subjectTag);
	}

	
	
}

ConcreteObserver.java

package com.observer.classic;

public class ConcreteObserver implements Observer {
	//观察者姓名
	private String observerName;
	
	//观察者兴趣点
	private String observerInterest;
	
	//观察者状态信息
	private String observerState;
	
	
	public String getObserverName() {
		return observerName;
	}

	public void setObserverName(String observerName) {
		this.observerName = observerName;
	}
	
	public String getObserverState() {
		return this.observerState;
	}
	
	public String getObserverInterest() {
		return observerInterest;
	}
	
	public void setObserverInterest(String observerInterest) {
		this.observerInterest = observerInterest;
	}
	
	
	@Override
	public void update(Subject subject) {
		//获取目标状态,以保持更新
		observerState = ((ConcreteSubject) subject).getSubjectState();
		System.out.println(observerName + "收到了一条通知:" + observerState);
	}


}


Test.java

package com.observer.classic;

public class Test {

	public static void main(String[] args) {
		
		
		// 创建推送内容1
		ConcreteSubject concreteSubject = new ConcreteSubject();
		
		// 创建观察者(即待通知对象)
		ConcreteObserver concreteObserver1 = new ConcreteObserver();
		concreteObserver1.setObserverName("张三");
		concreteObserver1.setObserverInterest("All");
		
		ConcreteObserver concreteObserver2 = new ConcreteObserver();
		concreteObserver2.setObserverName("李四");
		concreteObserver2.setObserverInterest("Music");
		
		ConcreteObserver concreteObserver3 = new ConcreteObserver();
		concreteObserver3.setObserverName("王二麻子");
		concreteObserver3.setObserverInterest("Sport");
		
		ConcreteObserver concreteObserver4 = new ConcreteObserver();
		concreteObserver4.setObserverName("刘老五");
		concreteObserver4.setObserverInterest("Movie");
		
		//注册观察者
		concreteSubject.attach(concreteObserver1);
		concreteSubject.attach(concreteObserver2);
		concreteSubject.attach(concreteObserver3);
		concreteSubject.attach(concreteObserver4);
		
		//发布通知1
		System.out.println("消息一:");
		concreteSubject.setSubjectState("周杰伦发了一张新专辑《哎哟,不错哦》","Music");
		
		//发布通知2
		System.out.println("消息二:");
		concreteSubject.setSubjectState("姚明宣布退役了","Sport");
		
		//发布通知3
		System.out.println("消息三:");
		concreteSubject.setSubjectState("新电影《栀子花开》上映了","Movie");
		
	}
}

运行结果

消息一:

李四收到了一条通知:周杰伦发了一张新专辑《哎哟,不错哦》

张三收到了一条通知:周杰伦发了一张新专辑《哎哟,不错哦》

消息二:

王二麻子收到了一条通知:姚明宣布退役了

张三收到了一条通知:姚明宣布退役了

消息三:

刘老五收到了一条通知:新电影《栀子花开》上映了

张三收到了一条通知:新电影《栀子花开》上映了


下面使用另外一种方法来实现有区分的观察者,即把notifyObservers方法交由子类去实现,而父类仅仅提供抽象方法。

WeatherSubject.java

package com.observer.advanced;
/**
 * 观察者模式的高级
 * 允许推送内容到特定的观察者
 * notifyObservers()在子类中实现
 */
import java.util.ArrayList;
import java.util.List;

public abstract class WeatherSubject {

	List<Observer> observers = new ArrayList<Observer>();
	
	public void attach(Observer observer) {
		observers.add(observer);
	}
	
	public void detach(Observer observer) {
		observers.remove(observer);
	}
	
	//留到子类中去实现
	protected abstract void notifyObservers();
}

ConcreteWeatherSubject.java

package com.observer.advanced;



public class ConcreteWeatherSubject extends WeatherSubject {

	//目标状态
	private String subjectState;
	
	
	public ConcreteWeatherSubject(String subjectState) {
		super();
		this.subjectState = subjectState;
	}

	public String getSubjectState() {
		return subjectState;
	}

	public void setSubjectState(String subjectState) {
		this.subjectState = subjectState;
		
		//一旦目标得到修改,所有的观察者都会收到通知
		this.notifyObservers();
	}

	@Override
	protected void notifyObservers() {
		/**
		 * 由于张三只接受下雪的天气预报,李四只接受下雨的天气预报,其他观察者无限制
		 */
		for(Observer observer : observers) {
			if("下雪".equals(subjectState)) {
				if("张三".equals(observer.getObserverName()))
					observer.update(this);
				else if(!"李四".equals(observer.getObserverName()))
					observer.update(this);
			}
			else if("下雨".equals(subjectState)) {
				if("李四".equals(observer.getObserverName()))
					observer.update(this);
				else if(!"张三".equals(observer.getObserverName()))
					observer.update(this);
			}
			else
				if(!"李四".equals(observer.getObserverName())&&!"张三".equals(observer.getObserverName()))
					observer.update(this);
		}
	}

}

Observer.java

package com.observer.advanced;

public interface Observer {

	public void update(WeatherSubject subject);
	
	//设置观察者名称
	public String getObserverName();
	
	public void setObserverName(String observerName);
	
	public String getObserverSex();
	
	public void setObserverSex(String observerSex);
	
	public String getObserverAge();
	
	public void setObserverAge(String observerAge);
}

ConcreteObserver.java

package com.observer.advanced;

public class ConcreteObserver implements Observer {

	private String observerName;
	
	private String observerSex;
	
	private String observerAge;
	
	
	public ConcreteObserver(String observerName, String observerSex,
			String observerAge) {
		super();
		this.observerName = observerName;
		this.observerSex = observerSex;
		this.observerAge = observerAge;
	}

	@Override
	public void update(WeatherSubject subject) {
		// 推送内容
		
		String content = ((ConcreteWeatherSubject)subject).getSubjectState();
			System.out.println(this.getObserverName()+"("+this.getObserverSex()+","+this.getObserverAge()+")收到了一条消息:"+content);
	}

	@Override
	public String getObserverName() {
		return observerName;
	}

	@Override
	public void setObserverName(String observerName) {
		this.observerName = observerName;
	}

	public String getObserverAge() {
		return observerAge;
	}

	public void setObserverAge(String observerAge) {
		this.observerAge = observerAge;
	}

	public String getObserverSex() {
		return observerSex;
	}

	public void setObserverSex(String observerSex) {
		this.observerSex = observerSex;
	}

}

Test.java

package com.observer.advanced;

public class Test {

	public static void main(String[] args) {
		//新建三个观察者
		Observer concreteObserver1 = new ConcreteObserver("张三", "男", "22岁");
		Observer concreteObserver2 = new ConcreteObserver("李四", "男", "30岁");
		Observer concreteObserver3 = new ConcreteObserver("玛丽", "女", "25岁");
	
		//新建目标内容:下雪
		WeatherSubject concreteWeatherSubject1 = new ConcreteWeatherSubject("下雪");
		concreteWeatherSubject1.attach(concreteObserver1);
		concreteWeatherSubject1.attach(concreteObserver2);
		concreteWeatherSubject1.attach(concreteObserver3);
		concreteWeatherSubject1.notifyObservers();
		
		//新建目标内容:下雨
		WeatherSubject concreteWeatherSubject2 = new ConcreteWeatherSubject("下雨");
		concreteWeatherSubject2.attach(concreteObserver1);
		concreteWeatherSubject2.attach(concreteObserver2);
		concreteWeatherSubject2.attach(concreteObserver3);
		concreteWeatherSubject2.notifyObservers();
		
		//新建目标内容:晴天
		WeatherSubject concreteWeatherSubject3 = new ConcreteWeatherSubject("晴天");
		concreteWeatherSubject3.attach(concreteObserver1);
		concreteWeatherSubject3.attach(concreteObserver2);
		concreteWeatherSubject3.attach(concreteObserver3);
		concreteWeatherSubject3.notifyObservers();
	
	}
}


运行结果:

张三(男,22岁)收到了一条消息:下雪

玛丽(女,25岁)收到了一条消息:下雪

李四(男,30岁)收到了一条消息:下雨

玛丽(女,25岁)收到了一条消息:下雨

玛丽(女,25岁)收到了一条消息:晴天


Java设计模式之观察者模式

标签:

原文地址:http://my.oschina.net/zzw922cn/blog/483089

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