设计模式之观察者模式

1.定义

观察者模式定义了对象之间的一对多依赖。当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

2.推模型和拉模型

观察者模式实现的两种方式:推模型和拉模型。

推模型:
主题对象主动向观察者推送主题的详细信息,推送的信息通常是主题对象的全部或部分数据。

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

两种模型比较:
推模型是假定主题对象知道观察者需要什么数据。会使观察者对象难以复用。
拉模型是主题对象不知道观察者具体需要什么数据,因此把自身传给观察者,由观察者来取值。update方法的参数是主题对象本身,基本上可以适用各种情况的需要。

3.观察者模式优缺点

优点:
(1)观察者模式实现了观察者和主题之间的松耦合,它们可以交互,但是不太清楚彼此的细节。
当有新类型的观察者出现时,主题的代码不需要修改。所要做的就是让新类实现观察者接口,然后注册为观察者即可。
如果在其他地方需要使用主题或观察者,可以轻易地复用,因为两者并非紧耦合。
(2)观察者模式实现了动态联动
(3)观察者模式支持广播通信
缺点:
可能引起无谓的操作或误更新

4.推模型实现

/*
 * 主题父类
 */
public class Subject {
	//观察者列表
	private List<Observer> observers = new ArrayList<Observer>();

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

	//删除观察者
	public void removeObserver(Observer observer) {
		observers.remove(observer);
	}
	
	//通知观察者
	protected void notifyObservers(String content) {
		for (Observer observer : observers) {
			observer.update(content);
		}
	}
}
/*
 * 主题具体实现
 */
public class ConcreteSubject extends Subject {
	//主题内容
	private String subjectContent;

	public String getSubjectContent() {
		return subjectContent;
	}

	public void setSubjectContent(String subjectContent) {
		this.subjectContent = subjectContent;
		//主题内容改变时,通知所有观察者
		this.notifyObservers(subjectContent);
	}
}
/*
 * 观察者接口
 */
public interface Observer {
	//更新观察者信息
	public void update(String content);
}
/*
 * 观察者具体实现
 */
public class ConcreteObserver implements Observer {
	//观察者名称
	private String observerName;
	
	//观察者内容
	private String observerContent;
	
	public String getObserverName() {
		return observerName;
	}

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

	public String getObserverContent() {
		return observerContent;
	}

	public void setObserverContent(String observerContent) {
		this.observerContent = observerContent;
	}

	@Override
	public void update(String content) {
		observerContent = content;
		System.out.println(observerName + ":" + observerContent);
	}
}
/*
 * 测试类
 */
public class Test {
	public static void main(String[] args) {
		//1.创建主题对象
		ConcreteSubject s = new ConcreteSubject();
		
		//2.创建观察者对象
		ConcreteObserver o1 = new ConcreteObserver();
		o1.setObserverName("小明");
		ConcreteObserver o2 = new ConcreteObserver();
		o2.setObserverName("小红");
		
		//3.注册观察者
		s.registerObserver(o1);
		s.registerObserver(o2);
		
		//4.主题内容发布
		s.setSubjectContent("吃饭了");
	}
}

5.拉模型实现

import java.util.ArrayList;
import java.util.List;
/*
 * 主题父类
 */
public class Subject {
	//观察者列表
	private List<Observer> observers = new ArrayList<Observer>();

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

	//删除观察者
	public void removeObserver(Observer observer) {
		observers.remove(observer);
	}
	
	//通知观察者
	protected void notifyObservers() {
		for (Observer observer : observers) {
			observer.update(this);
		}
	}
}
/*
 * 主题具体实现
 */
public class ConcreteSubject extends Subject {
	//主题内容
	private String subjectContent;

	public String getSubjectContent() {
		return subjectContent;
	}

	public void setSubjectContent(String subjectContent) {
		this.subjectContent = subjectContent;
		//主题内容改变时,通知所有观察者
		this.notifyObservers();
	}
}
/*
 * 观察者接口
 */
public interface Observer {
	//更新观察者信息
	public void update(Subject subject);
}
/*
 * 观察者具体实现
 */
public class ConcreteObserver implements Observer {
	//观察者名称
	private String observerName;
	
	//观察者内容
	private String observerContent;
	
	public String getObserverName() {
		return observerName;
	}

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

	public String getObserverContent() {
		return observerContent;
	}

	public void setObserverContent(String observerContent) {
		this.observerContent = observerContent;
	}

	@Override
	public void update(Subject subject) {
		observerContent = ((ConcreteSubject)subject).getSubjectContent();
		System.out.println(observerName + ":" + observerContent);
	}
}
/*
 * 测试类
 */
public class Test {
	public static void main(String[] args) {
		//1.创建主题对象
		ConcreteSubject s = new ConcreteSubject();
		
		//2.创建观察者对象
		ConcreteObserver o1 = new ConcreteObserver();
		o1.setObserverName("小明");
		ConcreteObserver o2 = new ConcreteObserver();
		o2.setObserverName("小红");
		
		//3.注册观察者
		s.registerObserver(o1);
		s.registerObserver(o2);
		
		//4.主题内容发布
		s.setSubjectContent("吃饭了");
	}
}

6.观察者模式的Java实现

Java实现与自己实现的几点不同:
(1)不需要再定义主题和观察者的接口了,JDK帮忙定义了。
(2)具体的主题实现里面不需要在维护观察者的注册信息了,Java中的Observable类里面已经帮忙实现好了。
(3)触发通知的方式有一点变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能。
(4)具体观察者实现里面,update方法能同时支持推模型和拉模型,这是Java在定义的时候,就已经考虑进去了。

import java.util.Observable;

/*
 * 主题具体实现
 */
public class ConcreteSubject extends Observable {
	// 主题内容
	private String subjectContent;

	public String getSubjectContent() {
		return subjectContent;
	}

	public void setSubjectContent(String subjectContent) {
		this.subjectContent = subjectContent;
		// 主题内容改变时,通知所有观察者
		// 注意在通知之前,在用Java的观察者模式的时候,下面这行代码不可少
		this.setChanged();
		// 推模型
//		this.notifyObservers(subjectContent);
		// 拉模型
		this.notifyObservers();
	}
}
import java.util.Observable;
import java.util.Observer;

/*
 * 观察者具体实现
 */
public class ConcreteObserver implements Observer {
	// 观察者名称
	private String observerName;

	// 观察者内容
	private String observerContent;

	public String getObserverName() {
		return observerName;
	}

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

	public String getObserverContent() {
		return observerContent;
	}

	public void setObserverContent(String observerContent) {
		this.observerContent = observerContent;
	}

	@Override
	public void update(Observable subject, Object content) {
		// 推模型
//		observerContent = (String)content;
		// 拉模型
		observerContent = ((ConcreteSubject)subject).getSubjectContent();
		System.out.println(observerName + ":" + observerContent);
	}
}
/*
 * 测试类
 */
public class Test {
	public static void main(String[] args) {
		//1.创建主题对象
		ConcreteSubject s = new ConcreteSubject();
		
		//2.创建观察者对象
		ConcreteObserver o1 = new ConcreteObserver();
		o1.setObserverName("小明");
		ConcreteObserver o2 = new ConcreteObserver();
		o2.setObserverName("小红");
		
		//3.注册观察者
		s.addObserver(o1);
		s.addObserver(o2);
		
		//4.主题内容发布
		s.setSubjectContent("吃饭了");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值