# 观察者模式

一直想写一篇学习观察者模式的总结没有契机，今天学习阻塞队列的原理时候看到在实现生产者消费者的时候用到了通知模式，就是所谓的观察者模式，正好顺便整理一下。

## 1. 简介

观察者模式定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。也就是 发布-订阅 的模式。

观察者模式涉及到的参与者有：

* **Subject（目标）：**&#x88AB;观察者的接口，提供注册/删除观察者和发通知的方法；
* **Observer（观察者）：**&#x89C2;察目标的对象接口，提供目标发生改变时需要处理更新的方法；
* **ConcreteSubject（具体目标）：**&#x5B9E;现被观察者接口的具体被观察者类，维护一个观察者的引用，在发通知的时候调用观察者的更新方法；
* **ConcreteObserver（具体观察者）：**&#x5B9E;现观察者接口的具体观察者类。

#### 观察者模式的使用场景

* 比如你微博关注了一个人，那么这个人发布的微博就会推送到你这。
* 还比如你关注了一个微信公众号，这个公众号发布的文章也会推送到你这。

## 2. 实例代码

就拿微博关注来举个例子，一些人关注了一个大V，那么大V每次发微博，这些人就会收到推送，哪天大V发的微博让某些人不爽了，果断取关，那么以后就不会收到大V的推送消息了。

### 新建Subject接口

```java
package con.wangjun.designPattern.observer;

public interface Subject {
    public void addFans(Observer o);  // 添加粉丝
    public void removeFans(Observer o);  // 移除粉丝
    public void notifyFans(String str);  // 通知粉丝
}
```

### 新建Observer接口

```java
package con.wangjun.designPattern.observer;

public interface Observer {
    // 当被观察者调用notifyFans发通知，update方法会被回调
    public void update(String str);
}
```

### 新建Subject实现类

```java
package con.wangjun.designPattern.observer;

import java.util.ArrayList;
import java.util.List;

public class VSubject implements Subject {

    List<Observer> list = new ArrayList<>();

    // 发布微博
    public void publish(String str) {
        System.out.println("大V发布微博：" + str);
        // 通知所有粉丝
        notifyFans(str);
    }

    @Override
    public void addFans(Observer o) {
        list.add(o);
    }

    @Override
    public void removeFans(Observer o) {
        list.remove(o);
    }

    @Override
    public void notifyFans(String str) {
        for(int i = 0; i < list.size(); i++) {
            list.get(i).update(str);
        }
    }

}
```

### 新建Observer实现类

```java
package con.wangjun.designPattern.observer;

public class FansObserver implements Observer {

    private String name;

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

    @Override
    public void update(String str) {
        System.out.println(name + " 收到大V的微博发文：" + str);
    }

}
```

### 新建测试类

```java
package con.wangjun.designPattern.observer;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        VSubject vs = new VSubject();  // 大V的实例  
        List<FansObserver> fans = new ArrayList<>();  //存储所有粉丝

        for(int i = 0; i < 5; i++) {
            FansObserver f = new FansObserver("name" + (i + 1));
            fans.add(f);
            vs.addFans(f);
        }
        // 本次发微博，5个粉丝都收到推送
        vs.publish("我的女朋友真好看！");
        // 居然秀恩爱，前2个粉丝，看不下去了，取关！
        for(int i = 0; i < 2; i++) {
            vs.removeFans(fans.get(i));
        }

        //这次发微博，那两个取关的人就看不到了
        vs.publish("我要送所有粉丝一部iPhone X");
    }
}
```

### 运行结果

```
大V发布微博：我的女朋友真好看！
name1 收到大V的微博发文：我的女朋友真好看！
name2 收到大V的微博发文：我的女朋友真好看！
name3 收到大V的微博发文：我的女朋友真好看！
name4 收到大V的微博发文：我的女朋友真好看！
name5 收到大V的微博发文：我的女朋友真好看！
大V发布微博：我要送所有粉丝一部iPhone X
name3 收到大V的微博发文：我要送所有粉丝一部iPhone X
name4 收到大V的微博发文：我要送所有粉丝一部iPhone X
name5 收到大V的微博发文：我要送所有粉丝一部iPhone X
```

> 参考：
>
> 《面向对象的设计模式》
>
> JAVA设计模式之观察者模式<https://www.cnblogs.com/luohanguo/p/7825656.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jun-wang.gitbook.io/learnjava/ji-shu-xue-xi/java-she-ji-mo-shi/guan-cha-zhe-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
