一、前言

本篇主题为行为型模式中的第四个模式–观察者模式。上篇 Java 设计模式主题为《Java 设计模式之迭代器模式(十五)》

二、简单介绍

# 2.1 定义

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

# 2.2 参与角色

  1. 被观察者(Subject):当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject 需要维持(添加,删除,通知)一个观察者对象的队列列表。

  2. 观察者(Observer):接口或抽象类。当 Subject 的状态发生变化时,Observer 对象将通过一个 callback 函数得到通知。

# 2.3 应用场景

  1. 聊天室程序,服务器转发信息给所有客户端。

  2. 网络游戏,服务器将客户端状态进行分发。

  3. 邮件订阅等。

三、实现方式

记得笔者在上中学时,所在的学校是禁止在寝室打扑克牌的,但是还是有不少学生违背这条规定,笔者就是其中之一。我们就以这个故事为例,在这个案例中,老师是被观察者,学生则是观察者。学生观察老师是否来到寝室,从而做出不同的行为。

被观察者和子类:

  1. public abstract class Subject {
  2. protected List<Observer> list = new ArrayList<Observer>();
  3. public void registerObserver(Observer obs) {
  4. list.add(obs);
  5. }
  6. public void removeObserver(Observer obs) {
  7. list.add(obs);
  8. }
  9. // 通知所有的观察者更新状态
  10. public void notifyAllObservers() {
  11. for (Observer obs : list) {
  12. obs.update(this);
  13. }
  14. }
  15. }
  16. public class Teacher extends Subject {
  17. private String action;
  18. public String getAction() {
  19. return action;
  20. }
  21. public void setAction(String action) {
  22. this.action = action;
  23. // 被观察者状态发生变化,通知观察者
  24. this.notifyAllObservers();
  25. }
  26. }

Teacher 继承 Subject 类,Teacher 的实例就是被观察的对象。

观察者和实现类:

  1. public interface Observer {
  2. public void update(Subject subject);
  3. }
  4. public class Student implements Observer {
  5. private String action;
  6. @Override
  7. public void update(Subject subject) {
  8. String teacherAction = ((Teacher) subject).getAction();
  9. if (teacherAction.equals("老师来了")) {
  10. action = "假装学习";
  11. } else if (teacherAction.equals("老师走了")) {
  12. action = "继续打牌";
  13. }
  14. }
  15. public String getAction() {
  16. return action;
  17. }
  18. }

客户端:

  1. public class Client {
  2. public static void main(String[] args) {
  3. Teacher teacher = new Teacher();
  4. Student s1 = new Student();
  5. Student s2 = new Student();
  6. Student s3 = new Student();
  7. teacher.registerObserver(s1);
  8. teacher.registerObserver(s2);
  9. teacher.registerObserver(s3);
  10. teacher.setAction("老师来了");
  11. System.out.println(s1.getAction());
  12. System.out.println(s2.getAction());
  13. System.out.println(s3.getAction());
  14. System.out.println("================");
  15. teacher.setAction("老师走了");
  16. System.out.println(s1.getAction());
  17. System.out.println(s2.getAction());
  18. System.out.println(s3.getAction());
  19. }
  20. }

打印结果:

  1. 假装学习
  2. 假装学习
  3. 假装学习
  4. ===========
  5. 继续打牌
  6. 继续打牌
  7. 继续打牌

其实,在 JDK 中已经提供了 java.util.Observable 和 java.util.Observer 来实观察者模式。

实现方式如下:

被观察者:

  1. public class Teacher extends Observable{
  2. private String action;
  3. public String getAction() {
  4. return action;
  5. }
  6. public void setAction(String action) {
  7. this.action = action;
  8. // 被观察者状态发生变化,通知观察者
  9. this.setChanged();
  10. this.notifyObservers(this.action);
  11. }
  12. }

观察者:

  1. public class Student implements Observer {
  2. private String action;
  3. @Override
  4. public void update(Observable o, Object arg) {
  5. String teacherAction = ((Teacher) o).getAction();
  6. if (teacherAction.equals("老师来了")) {
  7. action = "假装学习";
  8. } else if (teacherAction.equals("老师走了")) {
  9. action = "继续打牌";
  10. }
  11. }
  12. public String getAction() {
  13. return action;
  14. }
  15. }

客户端:

  1. public class Client {
  2. public static void main(String[] args) {
  3. Teacher teacher = new Teacher();
  4. Student s1 = new Student();
  5. Student s2 = new Student();
  6. Student s3 = new Student();
  7. teacher.addObserver(s1);
  8. teacher.addObserver(s2);
  9. teacher.addObserver(s3);
  10. teacher.setAction("老师来了");
  11. System.out.println(s1.getAction());
  12. System.out.println(s2.getAction());
  13. System.out.println(s3.getAction());
  14. System.out.println("================");
  15. teacher.setAction("老师走了");
  16. System.out.println(s1.getAction());
  17. System.out.println(s2.getAction());
  18. System.out.println(s3.getAction());
  19. }
  20. }

打印结果与上文的一致。

使用 JDK 提供的这 2 个类大大的简化了代码量。

UML 类图表示如下: