Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。
解决问题:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。使用面向对象技术,可以将这种依赖关系弱化。
应用实例:
1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。
2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
3、侦听事件驱动程序设计中的外部事件
4、侦听/监视某个对象的状态变化
5、发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者
观察者模式UML结构图:
角色和职责:
Subject(被观察者): 被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
ConcreteSubject:被观察者的具体实现。包含一些基本的属性状态及其他操作。
Observer(观察者): 接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
ConcreteObserver: 观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。以微信公众号和关注着为例,实现观察者模式。
定义观察者接口:
/**
* 抽象观察者
* 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
*/
public interface Observer {
public void update(String message);
}
定义被观察者接口:
/**
* 抽象被观察者接口
* 声明了添加、删除通知观察者方法
*
*/
public interface Observerable {
public void registerObserver(Observer observer);
public void unregisterObserver(Observer observer);
public void notifyObserver();
}
实现被观察者:
/**
* 被观察者,比如微信公众号服务
* 实现了Observerable接口,并实现其方法
*
*/
public class WechatServer implements Observerable {
private List<Observer> list;
private String message;
public WechatServer(){
list = new ArrayList<Observer>();
}
public void registerObserver(Observer observer) {
list.add(observer);
}
public void unregisterObserver(Observer observer) {
if (!list.isEmpty()) {
list.remove(observer);
}
}
//遍历所有的observer,进行notify
public void notifyObserver() {
for(Observer observer : list){
observer.update(message);
}
}
public void setInformation(String message){
this.message = message;
System.out.println("公众号更新了消息:" + message);
//更新消息,通知所有的关注着
notifyObserver();
}
}
实现观察者:
/**
* 定义具体的观察者,比如公众号的关注着
*
*/
public class User implements Observer {
private String name;
private String message;
public User(String name){
this.name = name;
}
public void update(String message) {
this.message = message;
read();
}
public void read(){
System.out.println(name + "收到推送消息" + message);
}
}
测试类:
public class MainClass {
public static void main(String[] args) {
WechatServer subject = new WechatServer();
Observer userZhang = new User("zhangsan");
Observer userLi = new User("lisi");
Observer userWang = new User("wangwu");
subject.registerObserver(userZhang);
subject.registerObserver(userLi);
subject.registerObserver(userWang);
subject.setInformation("我发了一个消息");
System.out.println("******************************************");
subject.unregisterObserver(userZhang);
subject.setInformation("我又发了一条消息");
}
}
测试结果:
公众号更新了消息:我发了一个消息
zhangsan收到推送消息我发了一个消息
lisi收到推送消息我发了一个消息
wangwu收到推送消息我发了一个消息
******************************************
公众号更新了消息:我又发了一条消息
lisi收到推送消息我又发了一条消息
wangwu收到推送消息我又发了一条消息
观察者模式优缺点:
优点:
1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。
缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。