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("吃饭了");
}
}