1. 定义及特点

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

意图:创建了对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新。

主要解决的问题:观察者模式解决的是一个对象状态改变时,如何自动通知其他依赖对象的问题,同时保持对象间的低耦合和高协作性。

举例:某公司发布了一款新的手机,性能很强大,许多人都想买,但是该公司又没宣布售卖时间。想买的人为了第一时间就拥有这台手机,就必须每天到官网或线下实体店看有没有出售,这样对于用户来说体验很不好。如果不想频繁的去查看,这时想买手机的用户就可以在实体店或网站上留下联系方式,等到手机出售的当天公司通过邮件或者短信的形式通知到购买者。

优点

  • 符合开闭原则。 无需修改发布者代码就能引入新的观察者类 。
  • 可以在运行时建立对象之间的联系。

缺点

  • 无法设置订阅者收到的顺序。
  • 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
  • 可能导致循环调用和系统崩溃。

2. 适用场景

观察者模式主要适用于以下场景:

  • 一对多依赖关系:当一个对象的状态改变时,需要自动通知并更新多个依赖对象。
  • 广播通信:事件驱动的系统,如消息队列、通知系统等,需要将事件或消息广播给所有订阅者。
  • 解耦对象:实现对象之间的松耦合,使得对象之间不必相互了解对方的具体实现,只需知道彼此的通知接口。
  • 动态更新:在GUI(图形用户界面)编程中,用户界面需要动态地根据模型数据的变化进行更新。

3. 模式的结构

观察者模式的主要角色如下:

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

观察者模式结构图:

观察者模式的结构图

4. 代码实现

根据以上结构图,我们可以编写出以下代码:

首先需要一个观察者接口:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 观察者接口
*
* @author 木又枯了
* @since 2024/10/16 8:14
**/
public interface Observer {
/**
* 观察者需做出的反应
*/
void response();
}

根据这个接口,编写出两个具体的观察者:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 观察者1号
*
* @author 木又枯了
* @since 2024/10/16 8:15
**/
public class ConcreteObserverOne implements Observer {
@Override
public void response() {
System.out.println("观察者1号做出响应...");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 观察者2号
*
* @author 木又枯了
* @since 2024/10/16 8:15
**/
public class ConcreteObserverTwo implements Observer {
@Override
public void response() {
System.out.println("观察者2号做出响应...");
}
}

再编写一个抽象目标类,也就是被观察者,在这里面需要创建一个 ArrayList 对象来存放观察者们:

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
/**
* 抽象目标类(被观察者的抽象类)
*
* @author 木又枯了
* @since 2024/10/16 8:20
**/
public abstract class Subject {

protected List<Observer> observers = new ArrayList<>();

/**
* 增加观察者
*
* @param observer 增加的观察者
*/
public void add(Observer observer) {
observers.add(observer);
}

/**
* 删除观察者
*
* @param observer 删除的观察者
*/
public void remove(Observer observer) {
observers.remove(observer);
}

/**
* 通知观察者
*/
public abstract void notifyObserver();
}

根据这个抽象目标类,完成具体目标(具体被观察者)的编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 具体目标(被观察者)
*
* @author 木又枯了
* @since 2024/10/16 8:25
**/
public class ConcreteSubject extends Subject {
@Override
public void notifyObserver() {
// 通知观察者,让观察者做出响应
for (Observer obs : observers) {
obs.response();
}
}
}

编写方法测试:

1
2
3
4
5
6
7
8
9
10
@Test
public void testObserverPattern() {
// 获取主题(获取被观察者)
ConcreteSubject subject = new ConcreteSubject();
// 为其设置观察者
subject.add(new ConcreteObserverOne());
subject.add(new ConcreteObserverTwo());
// 通知观察者做出响应
subject.notifyObserver();
}

运行测试方法后,控制台打印:

1
2
观察者1号做出响应...
观察者2号做出响应...