## 1 概述

又被称为**发布-订阅**（Publish/Subscribe）模式，它定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时，会通知所有的观察者对象，使他们能够自动更新自己。

在观察者模式中有如下角色：

- Subject：抽象主题（抽象被观察者），抽象主题角色把所有观察者对象保存在一个集合里，每个主题都可以有任意数量的观察者，抽象主题提供一个接口，可以增加和删除观察者对象。
- ConcreteSubject：具体主题（具体被观察者），该角色将有关状态存入具体观察者对象，在具体主题的内部状态发生改变时，给所有注册过的观察者发送通知。
- Observer：抽象观察者，是观察者的抽象类，它定义了一个更新接口，使得在得到主题更改通知时更新自己。
- ConcrereObserver：具体观察者，实现抽象观察者定义的更新接口，以便在得到主题更改通知时更新自身的状态。

## 2 例子

订阅新闻，新闻有更新，订阅者就会收到通知。

```java
//观察者
public interface Observer {
    void update(String msg);
}
//具体观察者
public class User implements Observer {
    private String name;

    public User(String name) {
        this.name = name;
    }

    @Override
    public void update(String msg) {
        System.out.println("尊敬的" + name + "：" + msg);
    }
}

//抽象被观察者
public interface Subject {
    //增加订阅者
    void attach(Observer observer);

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

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

//具体被观察者
public class SubscriptionSubject implements Subject {

    private List<Observer> users = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        users.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        users.remove(observer);
    }

    @Override
    public void notify(String message) {
        //通知给订阅者
        for (Observer observer : users) {
            observer.update(message);
        }
    }
}

//客户端
public class TestClient {
    public static void main(String[] args) {
        final User aa = new User("AA");
        final User bb = new User("BB");

        final SubscriptionSubject subscriptionSubject = new SubscriptionSubject();
        subscriptionSubject.attach(aa);
        subscriptionSubject.attach(bb);

        subscriptionSubject.notify("订阅更新了");
    }
}

```

## 3 优缺点

优点：

- 降低了目标与观察者之间的耦合关系，两者之间是抽象耦合关系。
- 被观察者发送通知，所有注册的观察者都会收到信息 - 可以实现广播机制

缺点：

- 如果观察者非常多的话，那么所有的观察者收到被观察者发送的通知会耗时
- 如果被观察者有循环依赖的话，那么被观察者发送通知会使观察者循环调用，会导致系统崩溃