观察者模式
# 观察者模式
## 观察者模式
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
属于行为型模式
## 类图

### ISubject
```text
public interface ISubject<E> {
boolean attach(IObserver<E> observer);
boolean detach(IObserver<E> observer);
void notify(E event);
}
```
### ConcreteSubject
```text
public class ConcreteSubject<E> implements ISubject<E> {
private List<IObserver<E>> observers = new ArrayList<>();
@Override
public boolean attach(IObserver<E> observer) {
if (this.observers.contains(observer)) {
return false;
}
observers.add(observer);
return true;
}
@Override
public boolean detach(IObserver<E> observer) {
return this.observers.remove(observer);
}
@Override
public void notify(E event) {
for (IObserver observer : observers) {
observer.update(event);
}
}
}
```
### IObserver
```text
public interface IObserver<E> {
void update(E event);
}
```
### ConcreteObserver
```text
public class ConcreteObserver<E> implements IObserver<E> {
@Override
public void update(E event) {
System.err.println("receive event " + event);
}
}
```
### DemoTest
```text
public class DemoTest {
public static void main(String[] args) {
ISubject<String> subject = new ConcreteSubject<String>();
subject.attach(new ConcreteObserver<String>());
subject.attach(new ConcreteObserver<String>());
subject.attach(new ConcreteObserver<String>());
subject.notify("test");
}
}
```
## JDK实现观察者模式
> 比如有一个博客系统提供了问题社区,一个人提出问题,会有其他人收到这个消息;我们使用JDK来模拟一个简单的场景;

### Blog 被观察对象
```text
public class Blog extends Observable {
private Blog() {
}
private static final Blog blog = new Blog();
private String name = "IBLi Blog";
public static Blog getInstance() {
return blog;
}
public void question(Question question) {
System.out.println(question.getUserName() + " 在 blog 提交了问题 : " + question.getContent());
setChanged();
notifyObservers(question);
}
}
```
### Question
```text
public class Question {
private String userName;
private String content;
public Question(String userName, String content) {
this.userName = userName;
this.content = content;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
```
### Student 学生类 被通知对象
```text
public class Student implements Observer {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
*/
@Override
public void update(Observable o, Object arg) {
Blog blog = (Blog) o;
Question question = (Question) arg;
System.out.println("******************");
System.out.println(this.name + " 看到了 " + question.getUserName() + " 的问题 \n" + "问题是: " + question.getContent());
}
}
```
### Client 测试
```text
public class Client {
public static void main(String[] args) {
Blog blog = Blog.getInstance();
blog.addObserver(new Student("Tom"));
blog.addObserver(new Student("John"));
Question question = new Question("小明","观察者模式是什么?");
blog.question(question);
}
}
```
### 测试结果
```text
小明 在 blog 提交了问题 : 观察者模式是什么?
******************
John看到了 小明 的问题
问题是: 观察者模式是什么?
******************
Tom看到了 小明 的问题
问题是: 观察者模式是什么?
```
## 基于Guava实现观察者模式
### Student 被观察对象
```text
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
@Subscribe
public void Observer(Student str) {
System.err.println("student invoke method + " + str.toString());
}
}
```
### Teacher 被通知对象
```text
public class Teacher {
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
@Subscribe
public void Observer(Teacher str) {
System.err.println("teacher invoke method + " + str.toString());
}
}
```
### Client 测试类
```text
public class Client {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
Student student = new Student("Ibli");
Teacher teacher = new Teacher("laoshi");
eventBus.register(student);
eventBus.register(teacher);
eventBus.post(new Student("xuesheng"));
eventBus.post(new Teacher("teacher"));
}
}
```
### 测试结果
```text
student invoke method + Student{name='xuesheng'}
teacher invoke method + Teacher{name='teacher'}
```
## 观察者模式使用场景
1、当一个抽象模型包含两个方面内容,其中一个方面依赖另一个方面
2、其他一个或多个对象的变化依赖另一个对象的变化
3、实现类似广播机制的功能,无需知道具体收听者,只需要广播。系统中感兴趣的对象会自动接口该广播
4、多层级嵌套机制,形成一种链式出发机制,是的时间具备跨域(跨越两种观察者类型)通知
## 观察者模式优点✅
1、降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
2、目标与观察者之间建立了一套触发机制。
## 观察者模式缺点
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。