有高尚思想的人永不会孤独的。 — 西德尼
写在前面
观察者模式的定义:定义对象间一种一对多的依赖关系,每当一个对象改变状态时,则所有依赖它的对象都会得到通知并被自动更新。
观察者模式.jpg
抽象被观察者类(Subject):把所有的观察者对象保存在一个集合里,每个被观察者都可以由任意数量的观察者,抽象主题类提供一个接口,可以增加和删除观察者对象。
具体被观察者类(ConcreteSubject):该角色将有关状态存入具体观察者对象,在具体被观察者内部发生改变时,给所有注册过的观察者发送通知。
抽象观察者类(Observer):是观察者的抽象类,它定义了一个更新接口,使得在得到被观察者更改通知时更新自己。
具体观察者类(ConcreteObserver):实现抽象观察者定义的更新接口,以便在得到被观察者更改通知时更新自身的状态。
如何观察
下面通过一个例子来认识观察者模式:
小明,小红和李雷因为上课捣蛋被老师拉到办公司罚站了,老师不放他们谁也不能走,只能继续罚站,直到老师说“你们可以回去上课了”。
1.抽象观察者类
因为小明,小红和李雷都要等老师说“你们可以回去上课了”这个行为,也就是要等老师的通知,所以三名同学是观察者,观察老师何时放人,就要定义一个等待通知的接口。
/**
* 抽象观察者类
*/
public interface Observer {
void update();
}
2.具体观察者类
因为小明,小红和李雷都要等老师说“你们可以回去上课了”这个行为,所以要观察老师的行为,每个人都要实现等待通知的接口。
/**
* 具体观察者类
*/
public class XiaoMingObserver implements Observer {
@Override
public void update() {
Log.d("小明", "小明可以回去继续上课了");
}
}
/**
* 具体观察者类
*/
public class XiaoHongObserver implements Observer {
@Override
public void update() {
Log.d("小红", "小红可以回去继续上课了");
}
}
/**
* 具体观察者类
*/
public class LiLeiObserver implements Observer {
@Override
public void update() {
Log.d("李雷", "李雷可以回去继续上课了");
}
}
3.抽象被观察者类
三名同学都要等待老师的通知,所以老师是被观察者。现来定义一个被观察者的接口。
/**
* 抽象被观察者
*/
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyAllObserver();
}
4.具体被观察者类
三名同学都要等待老师的通知,所以老师是被观察者。实现抽象被观察者类,并提供一个集合保存所有的观察者,以便向所有注册的观察者发送通知。
/**
* 具体被观察者类
*/
public class ConcreteSubject implements Subject {
private ArrayList<Observer> mObservers;
public ConcreteSubject() {
mObservers = new ArrayList<>();
}
@Override
public void attach(Observer observer) {
mObservers.add(observer);
}
@Override
public void detach(Observer observer) {
mObservers.remove(observer);
}
@Override
public void notifyAllObserver() {
for (Observer observer : mObservers) {
observer.update();
}
}
}
5.通知
老师心情突然好了,说了句“你们可以回去上课了”,三名同学得到了老师的通知,全部回到教室继续上课。
/**
* 客户端
*/
public class Client {
public Client() {
// 创建被观察者,向被观察者注册观察者
ConcreteSubject subject = new ConcreteSubject();
subject.attach(new XiaoMingObserver());
subject.attach(new XiaoHongObserver());
subject.attach(new LiLeiObserver());
// 被观察者发送通知
subject.notifyAllObserver();
}
}
总结
观察者模式的使用场景:
- 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列,事件总线的处理机制。
观察者模式的优点:
- 观察者和被观察者之间是抽象耦合,容易扩展。
- 方便建立一套触发机制。
观察者模式的缺点:
- 在应用观察者模式时需要考虑一下开发效率和运行效率问题。程序中包括一个被观察者,多个观察者,开发,调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步方式。