版权声明:本文为 冬夏 原创文章,可以随意转载,但请注明出处。
观察者模式(Observer)又称为发布-订阅(Publish-Subscribe)模式,它定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
观察者模式是日常开发中使用最广的设计模式之一,有许多开源库也用到了观察者模式,比如说: Rxjava,EventBus 等等。
观察者模式主要有以下几个特点:
- 观察者模式定义了对象之间一对多的关系
- 观察者和被观察者之间用松耦合的方式
- 观察者接收通知有两种方式,推和拉(推被认为更加正确)
那么怎么使用观察者模式呢?举一个例子
目前很火的微信公众号相信大家都不陌生,当我们关注了某一个公众号的之后,每当公众号有新文章的时候,我们都会自动接收到更新。但是公众号博主并不需要知道关注他公众号的每一个人究竟是谁。当我们想看这个公众号更多的文章时候,还可以点击「 历史文章 」进行查看。当我们取消对某一个公众号的关注之后,不管这个公众号以后有多少文章更新,我们都不会再收到了,除非我们再次关注这个公众号。
这个公众号的例子就是一个典型的观察者模式的应用实例。从这个例子里我们可以总结出观察者模式的使用流程。
- 注册(当我们关注了某个公众号的时候,实际上就是完成了注册的流程,我们告诉了该公众号「 我关注了你,以后你有新文章记得推送给我 」。)
- 通知(当我们接收到该公众号的新文章的时候,实际上就是完成了通知的流程,公众号告诉了我们「 我新发表了一篇文章,记得查收哦 」。)
- 拉取(当我们想查看该公众号更多的文章,点击了「历史文章」或其他按钮的时候,实际上就是完成了拉取的过程,我们告诉了该公众号「 我想看你其他的文章,你把链接发给我一下 」。)
- 解注册(当我们取消对某个公众号的关注的时候,实际上就是完成了解注册的流程,我们告诉了该公众号「 我不想再看你写的文章了,你以后都别推送给我了 」。)
接下来,我们通过一个简单的例子实现一下观察者模式
public interface Observer {
void update(Observerable observerable, Object obj);
}
public interface Observerable {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public class Publisher implements Observerable {
private String publisherName;
private List<Observer> observers = new ArrayList<>();
private List<String> articles = new ArrayList<>();
private String latestArticle = null;
public Publisher(@NotNull String name){
publisherName = name;
}
public String getPublisherName() {
return publisherName;
}
@Override
public void addObserver(Observer observer) {
if (!observers.contains(observer)){
observers.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
if (observers.contains(observer)){
observers.remove(observer);
}
}
@Override
public void notifyObservers() {
for (Observer observer : observers){
observer.update(this,latestArticle);
}
}
public void addNewArticle(String articleName){
articles.add(articleName);
latestArticle = articleName;
notifyObservers();
}
public List<String> getArticleList(){
return articles;
}
}
public class Reader implements Observer {
private String readerName;
List<Publisher> publishers = new ArrayList<>();
public Reader(@NotNull String name){
readerName = name;
}
public void follow(Publisher publisher){
if (!publishers.contains(publisher)){
publishers.add(publisher);
publisher.addObserver(this);
System.out.println("读者: " + readerName +
" 关注公众号:" + publisher.getPublisherName());
}
}
public void unfollow(Publisher publisher){
if (publishers.contains(publisher)){
publishers.remove(publisher);
publisher.removeObserver(this);
System.out.println("读者: " + readerName +
" 取消关注公众号:" + publisher.getPublisherName());
}
}
@Override
public void update(Observerable observerable, Object obj) {
System.out.println("读者: " + readerName
+ " 接收到公众号: " + ((Publisher)observerable).getPublisherName()
+ "的新文章: " + (String)obj);
}
public void getAllArticleByPublisher(Publisher publisher){
if (publishers.contains(publisher)){
publisher.getArticleList();
System.out.println("读者: " + readerName
+ " 获取公众号: " + publisher.getPublisherName()
+ "的所有文章");
}else {
System.out.println("没有关注该公众号");
}
}
}
public class Test {
public static void main(String[] args){
Publisher publisherA = new Publisher("公众号1");
Publisher publisherB = new Publisher("公众号2");
Reader readerA = new Reader("读者1");
Reader readerB = new Reader("读者2");
readerA.follow(publisherA);
publisherA.addNewArticle("设计模式之观察者模式");
readerB.follow(publisherA);
publisherA.addNewArticle("设计模式之单例模式");
publisherB.addNewArticle("设计模式之策略模式");
readerA.follow(publisherB);
readerA.unfollow(publisherA);
readerA.getAllArticleByPublisher(publisherA);
readerA.getAllArticleByPublisher(publisherB);
}
}
通过上面的代码,我们就可以模拟出公众号和读者的关注,推送,获取,取消关注四个操作。
上面的代码执行结果为:
读者: 读者1 关注公众号:公众号1
读者: 读者1 接收到公众号: 公众号1的新文章: 设计模式之观察者模式
读者: 读者2 关注公众号:公众号1
读者: 读者1 接收到公众号: 公众号1的新文章: 设计模式之单例模式
读者: 读者2 接收到公众号: 公众号1的新文章: 设计模式之单例模式
读者: 读者1 关注公众号:公众号2
读者: 读者1 取消关注公众号:公众号1
没有关注该公众号
读者: 读者1 获取公众号: 公众号2的所有文章
那么什么时候就应该使用观察者模式呢?
- 当一个模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
最后提一点,其实 Java 源码中的 「 java.util.Observer 」和 「 java.util.Observable 」 两个类就帮我们实现了观察者模式,但是有一点不同的是,「 java.util.Observable 」是类而不是接口,而 Java 的单继承机制就导致我们不能在继承「 java.util.Observable 」的时候同时又继承别的类。