每天一个设计模式:观察者模式 - Sanarous的博客

每天一个设计模式:观察者模式

观察者模式定义了对象之间一对多的关系,这样一来,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。

我们可以举个例子,比如报纸或者杂志的订阅,我们读者属于订阅者,报纸或者杂志属于出版者,那么:

  1. 向某家报纸社订阅报纸,只要他们有新报纸出版,就会给读者送过去,只要你是他的订阅者,那么你就一直会收到新报纸。
  2. 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸过来了。
  3. 只要报纸社还在运营,就会一直有人向他们订阅报纸或者取消订阅报纸。

以上就是一个典型的适用于观察者模式的案例,我们画个图说明一下:

对于这种一对多的关系,我们常用 Subject 和 Observer 接口的类设计来进行实现:

  • Subject:这是主题接口,对象使用此接口注册为观察者,或者自己从观察者中删除
  • Observer:所有潜在的观察者都必须实现观察者接口,这个接口只有 update() 一个方法,当主题状态改变时它被调用
  • ConcreteSubject:一个具体主题总是实现主题接口,除了注册和撤销方法之外,具体主题还实现了 notifyObserver() 方法,此方法用于在改变状态时更新所有当前的观察者
  • ConcreteObserver:具体的观察者可以是实现此接口的任意类,观察者必须注册具体主题,以便接收更新

观察者模式提供一种对象设计,让主题和观察者之间松耦合。我们可以在代码中随时实现一个实现了 Observer 接口的新观察者,运行时也可以使用新观察者取代现有的观察者,主题不会收到任何的影响,同样可以在任何时候删除某些观察者。

下面我们以微信公众号为例子,假设微信用户就是观察者,微信公众号是发布者,有多个用户关注了 Sanarous 这个公众号,当这个公众号更新时就会通知这些订阅者。

先抽象一个观察者:

1
2
3
public interface Observer{
public void update(String message);
}

然后定义一个具体的观察者实现观察者接口,这个接口实现了更新的方法:

1
2
3
4
5
6
7
8
9
10
11
12
public class VXUser implements Observer{
private String vxName;

public VXUser(String vxName){
this.vxName = vxName;
}

@Override
public void update(String message){
System.out.println(name + ",您专注的" + message);
}
}

有了观察者之后,我们再定义发布者,也就是微信公众号:

1
2
3
4
5
6
7
8
9
10
11
public interface Subject{

//增加订阅者
public void registerObserver(Observer observer);

//删除订阅者
public void removeObserver(Observer observer);

//更新消息时通知订阅者
public void notify(String message);
}

同上我们再定义一个具体的发布者类——微信公共号,内部维护了一个订阅该公众号的 list,并实现了接口中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class VXSubscriptionSubject implements Subject{
//存储订阅公众号的微信用户
private List<Observer> vxUserList = new ArrayList<>();

@Override
public void registerObserver(Observer observer){
vxUserList.add(observer);
}

@Override
public void removeObserver(Observer observer){
vxUserList.remove(observer);
}

@Override
public void notify(String message){
for(Observer ob : vxUserList){
observer.update(message);
}
}
}

以上就完成了整个观察者模式的基本功能,我们可以写一个客户端程序试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Client{
public static void main(String[] args){
VXSubscriptionSubject vxSub = new VXSubscriptionSubject();
//创建一个微信用户
VXUser user1 = new VXUser("码农人生");
VXUser user2 = new VXUser("kily-007");
VXUser user3 = new VXUser("Chenzy");

//订阅整个公众号
vxSub.registerObserver(user1);
vxSub.registerObserver(user2);
vxSub.registerObserver(user3);

//公共号发布新消息
vxSub.notify("Sanarous的专栏更新啦");
}
}

运行后输出的结果如下:

1
2
3
码农人生,您关注的Sanarous的专栏更新啦
kily-007,您关注的Sanarous的专栏更新啦
Chenzy,您关注的Sanarous的专栏更新啦

综上我们可以看到,观察者模式的实现接触了耦合,让双方都依赖于抽象,从而使得各自的变换都不会影响到另一方。但是在应用的时候需要考虑一下开发效率和运行效率的问题,程序中包含一个发布者,多个观察者,开发、调试等内容会比较复杂,而且在 Java 中消息的通知一般是顺序执行,那么一个观察者卡顿了,会影响整体的执行效率,在这种情况下需要使用异步实现。

如果这篇文章对您很有帮助,不妨
-------------    本文结束  感谢您的阅读    -------------
0%