观察者模式

定义

定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。
行为型

适用场景

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立的改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间大的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为影响C对象….,可以适用观察者模式创建一种链式触发机制。

优点和缺点

优点

  • 观察者和被观察者之间建立一个抽象的耦合
  • 观察者模式支持广播通信

缺点

  • 观察者时间有过多的细节依赖、提高时间消耗及程序复杂度
  • 使用要得当,要避免循环调用

结构

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

代码实现

自定义抽象类实现观察者

抽象目标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Subject {

protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法

}

具体目标:

1
2
3
4
5
6
7
8
9
public class ConcreteSubject extends Subject {
public void notifyObserver() {
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for (Object obs : observers) {
((Observer) obs).response();
}
}
}

抽象观察者

1
2
3
public interface Observer {
void response(); //反应
}

具体观察者1

1
2
3
4
5
public class ConcreteObserver1 implements Observer {
public void response() {
System.out.println("具体观察者1作出反应!");
}
}

具体观察者2

1
2
3
4
5
public class ConcreteObserver2 implements Observer {
public void response() {
System.out.println("具体观察者2作出反应!");
}
}

结果:

1
2
3
4
具体目标发生改变...
--------------
具体观察者1作出反应!
具体观察者2作出反应!

UML类图

使用jdk提供类实现观察者

假设一个场景,学生向老师提问问题,那么老师就是观察者,需要观察学生是否有问题并及时做出回应,学生就是被观察者
创建学生类,被观察者,继承jdk的Observable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Student extends Observable {
private String name;

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

public String getName() {
return name;
}

public void produceQuestion(String question){
System.out.println(name+" 同生提出了一个问题:"+question);
setChanged();
notifyObservers(question);
}

}

观察者老师,继承jdk的Observer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Teacher implements Observer {

private String name;

public Teacher(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Student student = (Student) o;
String question = (String) arg;
System.out.println(name+" 老师收到了一个 "+student.getName()+"同学提出的问题:"+question);
}
}

具体调用测试:

1
2
3
4
5
6
7
8
9
10
11
public class Test {

public static void main(String[] args) {
Student student = new Student("小明");
Teacher teacher = new Teacher("王老师");
Teacher teacher1 = new Teacher("刘老师");
student.addObserver(teacher);
student.addObserver(teacher1);
student.produceQuestion("天为什么是蓝的");
}
}

输出结果:

1
2
3
小明 同生提出了一个问题:天为什么是蓝的
刘老师 老师收到了一个 小明同学提出的问题:天为什么是蓝的
王老师 老师收到了一个 小明同学提出的问题:天为什么是蓝的

UML类图