定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。又叫做发布-订阅(Publish-Subscribe)模式。
场景
- 聊天室程序的创建。服务器创建好后,A、B、C三个用户上来公开聊天。A向服务器发送消息,服务器端聊天数据发生改变,希望这些数据分别发给其他在线客户,也就是每个客户端都需要更新服务端的聊天数据。
- 网站上多人订阅的“每日一笑”的新闻,当有这个主题新闻时,将消息发送给所有订阅者。
- 大家一起玩CS游戏时,服务器需要将每个人的方位信息变化发给所有玩家。
上面这些场景,我们都可以使用观察者模式来处理,可以将多个订阅者、客户称之为观察者;需要同步给多个观察者的数据封装到对象中,称之为目标。
核心
- 观察者模式主要用于1:N的通知,当一个对象(目标对象Subject或Observable)的状态变化时,他需要及时告诉一系列对象(观察者对象,Observer),令他们做出响应,
- 通知观察者的方式:
- 推
每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动接收。 - 拉
观察者只要知道有情况即可,至于什么时候获取内容,获取什么内容,都由自己决定。
- 推
结构图
- Observer:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时,更新自己。这个接口叫做更新接口,通常包含一个update方法,这个方法叫做更新方法。
- Subject:可叫做主题或者抽象通知者,一般由抽象类或者接口实现,它把所有对观察者对象的引用保存在一个容器中,每个主题都可以有任何数量的观察者,抽象主题可以提供增加和删除观察者的接口,还有一个广播消息的方法。
- ConcreteObserver:具体观察者,实现Observer,有自己的状态,但是一般根据主题的状态来自动更新,与主题状态保持一致。
- ConcreteSubject:具体主题类,有自己的状态,当状态变化时会通知所有观察者,观察者会及时更新自己的状态。
特点
- 使用观察者模式的动机:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是要维护相关对象之间的一致性,我们不希望为了维护一致性而使各个类之间紧密耦合,这样会给重用、维护、扩展都带来不便。而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数量的依赖它的Observer,一旦Subject的状态发生了改变,所有Observer都可以得到通知。Subject发出通知时,并不需要知道谁是它的观察者,也就是说具体观察者是谁,它根本不需要知道,而任何一个具体观察者不知道也不需要知道其他观察者的存在。
- 何时使用:当一个对象的改变同时需要改变其他对象时的时候,而且它不知道具体有多少对象要改变时,应该考虑使用观察者模式。
- 观察者模式所做的事其实就是在解除耦合,让耦合的双方都依赖与抽象,而不依赖与具体,从而使得各自的变化都不会直接的影响到另一边的改动。
模拟实现
- 观察者接口Observer
/**
* User:tumbler
* Desc:观察者模式--观察者接口,包含一个update更新方法来同步主题状态
*/
public interface Observer {
void update(Subject subject);
}
- 主题对象类Subject
/**
* User:tumbler
* Desc:观察者模式--主题类,定义所有观察者容器,注册和删除观察者方法,消息广播方法
*/
public class Subject {
protected List<Observer> list = new ArrayList<>();
public void registerObserver(Observer observer) {
list.add(observer);
}
public void removeObserver(Observer observer) {
list.remove(observer);
}
/**
* 通知所有观察者更新状态
*/
public void notifyAllObserver(){
for (Observer observer : list) {
observer.update(this);
}
}
}
- 具体主题对象ConcreteSubject
/**
* User:tumbler
* Desc:观察者模式--具体主题类
*/
public class ConcreteSubject extends Subject {
private int state;
public int getState() {
return state;
}
/**
* 主题对象状态发生变化时,通知所有观察者
* @param state
*/
public void setState(int state) {
this.state = state;
this.notifyAllObserver();
}
}
- 定义具体观察者ObserverA、ObserverB
/**
* User:tumbler
* Desc:观察者模式--具体观察者
*/
public class ObserverA implements Observer {
private int myState;
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
@Override
public void update(Subject subject) {
myState = ((ConcreteSubject)subject).getState();
}
}
/**
* User:tumbler
* Desc:观察者模式--具体观察者
*/
public class ObserverB implements Observer {
private int myState;
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
@Override
public void update(Subject subject) {
myState = ((ConcreteSubject)subject).getState();
}
}
- 测试
/**
* User:tumbler
* Desc:观察者模式--测试
*/
public class Client {
public static void main(String[] args) {
//主题对象
ConcreteSubject subject = new ConcreteSubject();
//观察者对象
ObserverA observerA = new ObserverA();
ObserverB observerB = new ObserverB();
//将观察者对象注册到主题对象中
subject.registerObserver(observerA);
subject.registerObserver(observerB);
//改变主题对象subject的状态,看观察者的状态
System.out.println("------------改变状态");
subject.setState(888);
System.out.println(observerA.getMyState()); //888
System.out.println(observerB.getMyState()); //888
System.out.println("------------改变状态");
subject.setState(999);
System.out.println(observerA.getMyState()); //999
System.out.println(observerB.getMyState()); //999
}
}
- UML图
使用java的Observable和Observer
javaSE提供了java.util.Observable和java.util.Observer来实现观察者模式。
- 定义主题对象,继承Observable类
import java.util.Observable;
/**
* User:tumbler
* Desc:观察者模式--主题对象
*/
public class ConcreteSubject extends Observable {
private int state;
/**
* 主题对象的状态发生改变,
* 并调用父类setChanged方法表示状态已发送改变
* 通知观察者notifyObservers
* @param state
*/
public void setState(int state) {
this.state = state;
setChanged();
notifyObservers(state);
}
public int getState() {
return state;
}
}
- 定义观察者对象,实现Observer接口
import java.util.Observable;
import java.util.Observer;
/**
* User:tumbler
* Desc:观察者模式--具体观察者
*/
public class ObserverA implements Observer {
private int myState;
public int getMyState() {
return myState;
}
@Override
public void update(Observable o, Object arg) {
myState = ((ConcreteSubject)o).getState();
}
}
- 测试
/**
* User:tumbler
* Desc:观察者模式--测试
*/
public class Client {
public static void main(String[] args) {
//定义主题对象
ConcreteSubject subject = new ConcreteSubject();
//定义观察者对象
ObserverA observerA = new ObserverA();
ObserverA observerB = new ObserverA();
//将观察者添加到主题对象中
subject.addObserver(observerA);
subject.addObserver(observerB);
//改变主题的状态,看观察者状态的改变
subject.setState(666);
System.out.println(observerA.getMyState()); //666
System.out.println(observerB.getMyState()); //666
}
}