一、定义及组成部分
1.定义
观察者(Observer)模式 又名发布-订阅(Publish/Subscribe)模式。GOF 给观察者模式如下定义:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2. 组成部分
观察者模式由以下几部分组成:
- Subject:抽象主题(抽象被观察者)抽象主题角色把所有观察者对象放进一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
观察者模式结构图
二、观察者模式的简单实现
观察者模式这种发布-订阅的形式我们可以拿微信公众号来举例,假设微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号,当这个公众号更新时就会通知这些订阅的微信用户。好了我们来看看用代码如何实现:
1.抽象观察者(Observer)
里面定义了一个更新的方法:
package observer;
//抽象观察者,定义一个update方法,用来更新消息
public interface Observer {
public void update(String message);
}
2.具体观察者(ConcrereObserver)
微信用户是观察者,里面实现了更新的方法:
package observer.impl;
import observer.Observer;
//具体的观察者,如微信用户
public class WeChatUser implements Observer {
private String name;//用户名字
public WeChatUser(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name+"!"+message);
}
}
3.抽象被观察者(Subject)
抽象主题,提供了add、delete、notify三个方法:
package observer;
//抽象被观察者,提供增加,删除,通知观察者三个方法
public interface Subject {
public void add(Observer observer);
public void delete(Observer observer);
public void notify(String message);
}
4.具体被观察者(ConcreteSubject)
微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法:
package observer.impl;
import observer.Observer;
import observer.Subject;
import java.util.ArrayList;
import java.util.List;
//具体被观察者,如微信公众号
public class WeChatSubscription implements Subject {
private List<Observer> list=new ArrayList<>();//存储具体观察者的列表
@Override
public void add(Observer observer) {
list.add(observer);
}
@Override
public void delete(Observer observer) {
list.remove(observer);
}
@Override
public void notify(String message) {
for(Observer user:list){
user.update(message);
}
}
}
测试:
package observer;
import observer.impl.WeChatSubscription;
import observer.impl.WeChatUser;
public class test {
public static void main(String[] args) {
//创建微信公众号
WeChatSubscription weChatSubscription = new WeChatSubscription();
//创建微信用户
WeChatUser user1 = new WeChatUser("张三");
WeChatUser user2 = new WeChatUser("李四");
WeChatUser user3 = new WeChatUser("王五");
//订阅公众号
weChatSubscription.add(user1);
weChatSubscription.add(user2);
weChatSubscription.add(user3);
//公众号推送消息给微信用户
weChatSubscription.notify("刘望舒的专栏更新了");
}
}
结果:
张三!刘望舒的专栏更新了
李四!刘望舒的专栏更新了
王五!刘望舒的专栏更新了
三、 总结
1.观察者模式 主要解决了什么问题?
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
2.如何解决?
使用面向对象技术,可以将这种依赖关系弱化。
3.观察者模式 何时使用?
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
4.观察者模式 的优缺点
【优点】
① 观察者和被观察者是抽象耦合的。
② 建立一套触发机制。
【缺点】
① 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
②如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
③ 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
5.观察者模式 的使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
6.观察者模式 的注意事项
① JAVA 中已经有了对观察者模式的支持类。
② 避免循环引用。
③ 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。