行为模式之观察者模式

Posted by Night Field's Blog on May 10, 2020

1 概述

观察者模式(observer Pattern),也叫发布-订阅模式,是一种很重要的行为模式,它被广泛运用在异步编程之中,可以说是异步编程的基础。

2 观察者模式

当我们需要关注某个对象的状态时,可以不断地轮询,查看状态是否变化,这也就是我们熟知的同步方式。然而这样的方式效率很低,在对象状态真正变化之前,任何的检查都是对服务器资源的浪费。更好的方法是,当对象状态改变的时候,可以有一种通知机制,告诉别人状态发生了变化。观察者模式,正是实现这种机制的关键。

观察者模式中,观察者可以注册到自己感兴趣的被观察对象上,当被观察对象的状态发生变化,或某个事件放生时,逐个调用观察者的方法来通知它们。这种异步的方式,很大程度上提高了运行效率

现实生活中,观察者模式也很常见。比如网购了一件商品,我们不用时不时地去收货点查看快递有没有到,而是当收到“商品已送达”的短信的时候,直接去取就行。此例中,当我们购买商品的时候,相当于关注了快递的状态,当状态变为“已送达”的时候,我们会得到通知。

3 案例

举一个代码案例。当我们关注了某个公众号之后,便可以收到公众号的文章推送,这其实就是典型的观察者模式的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public interface Observable<T> {
    void addSubscriber(Observer observer);
    void removeSubscriber(Observer observer);
    void publish(T object);
}

public class PublicAccount implements Observable<Article> {
    private String name;
    private Collection<Observer> subscribers;
    private Collection<Article> articles;
    PublicAccount(String name) {
        this.name = name;
        subscribers = new ArrayList<>();
        articles = new LinkedList<>();
    };
    @Override
    public synchronized void addSubscriber(Observer observer) {
        subscribers.add(observer);
    }
    @Override
    public synchronized void removeSubscriber(Observer observer) {
        subscribers.remove(observer);
    }
    @Override
    public synchronized void publish(Article article) {
        articles.add(article);
        System.out.println(name + " is publishing new article...");
        for (Observer subscriber : subscribers) {
            subscriber.update(article);
        }
    }
}

public interface Observer<T> {
    void update(T object);
}

public class ArticleFans implements Observer<Article> {
    private String name;
    ArticleFans(String name) {
        this.name = name;
    };
    @Override
    public void update(Article article) {
        System.out.println(name + " got article「" + article.getName() + "」");
    }
}

public class Article {
    private String name;
    private String content;
    Article(String name, String content) {
        this.name = name;
        this. content = content;
    };
    public String getName() {
        return name;
    }
}

public class Test {
    public static void main(String[] args) {
        PublicAccount publicAccount = new PublicAccount("Jump x Switch");
        ArticleFans link = new ArticleFans("Link");
        ArticleFans mario = new ArticleFans("Mario");
        publicAccount.addSubscriber(link);
        publicAccount.addSubscriber(mario);

        Article article = new Article("Pro Controller is on discount!", "……");
        publicAccount.publish(article);
    }
}

输出:

1
2
3
Jump x Switch is publishing new article...
Link got article「Pro Controller is on discount!」
Mario got article「Pro Controller is on discount!」

我们关注了公众号,其实就是把自己加入了公众号的观察者列表,当公众号发布新文章的时候,所有关注它的人,都会得到文章的推送。

JDK中的java.util.Observablejava.util.Observer,是观察者模式的简单实现,不过现实中使用不多(在SWT中应用很多)。 观察者模式更多见于事件通知模型的框架中,如Netty中随处可见ChannelFutureGenericFutureListener的组合;也可见于RedisPub/SubZooKeeperWatches……

4 总结

观察者模式允许我们在对象状态改变时得到通知,在一些高性能框架中得到了广泛的应用,是异步编程的基础。

文中例子的github地址