观察者模式

定义

        简而言之,观察者模式定义了对象间一种一对多的依赖关系,当某个对象发生状态的变化后,任何关注此对象的观察者会得到通知。观察者模式也成订阅/发布模型,当csdner订阅了该博主,那么当该博主发布一篇博文后,csdner将收到博文的推送,csdner将抽空阅读该篇博文,甚至点击关注。(你们懂吧,疯狂暗示)。


简单实例

        以一个简单的例子来说明观察者模式是如何运作的,具体场景如下:

        在一个炎热的午后,主人正懒散的躺在躺椅上,尽情地感受阴凉。突然远处的流浪狗恶狠狠地叫了几声,猫听到后害怕极了,也叫了几声,主人听到狗叫声和猫叫声,以为发生了什么事情,便从躺椅上起来看看咋回事。此时躲在角落里的老鼠也听到了猫叫声,窜来窜去。

        在这个例子中,狗是被观察者,猫既是观察者也是被观察者,主人和老鼠则是观察者。


代码示例

        项目的类图如下:

        我们将被观察者的职责抽象成Subject,在这个类中,需要保存关注该被观察者的观察者集合,以及增加、删除观察者的方法,以及最重要的通知方法。任何被观察者都需要继承此类,这样只去考虑自己的逻辑方法即可。

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

/**
 * 被观察者的职责
 */
public class Subject {

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

    public void addObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    public void notifyObservers() {
        for (Observer observer:observers) {
            observer.update(this);
        }

    }
}

        将观察者的职责抽象成Observer接口,任何观察者都需要实现此接口。在该接口中,提供update方法,用于在接收到通知后,执行相应的处理方法。

/**
 * 观察者接口
 */
public interface Observer {

    void update(Subject s);
}

 

        其中狗作为被观察者:

/**
 * 狗仅是被观察者
 */
public class Dog extends Subject {

    public void bark() {
        System.out.println("狗叫了几声");
        super.notifyObservers();
    }

}

        猫既是被观察者也是观察者:

/**
 * 猫即是被观察者,也是观察者。
 * 猫被主人和老鼠观察,猫观察狗
 */
public class Cat extends Subject implements Observer {

    public void scream() {
        System.out.println("猫叫了几声");
        super.notifyObservers();
    }

    @Override
    public void update(Subject s) {
        if (s instanceof Dog) {
            System.out.println("猫听到了狗叫声,害怕得叫了起来");
            scream();
        }
    }
}

        老鼠是观察者:

/**
 * 老鼠仅是观察者
 */
public class Mouse implements Observer {

    @Override
    public void update(Subject s) {
        if (s instanceof Cat) {
            System.out.println("老鼠听到猫叫声,撒腿就跑");
        }
    }
}

        主人是观察者:

/**
 * 主人仅是观察者
 */
public class Person implements Observer {

    public void update(Subject s) {
        if (s instanceof Dog) {
            System.out.println("主人听到狗叫声,过去看看情况");
        } else if (s instanceof Cat) {
            System.out.println("主人听到猫叫声,过去看看情况");
        }
    }

}

        运行类:

/**
 * 2019/7/23 16:00
 * 观察者模式
 * 猫和主人观察狗,老鼠和主人观察猫
 */
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        Mouse mouse = new Mouse();
        Person person = new Person();
        
        dog.addObserver(cat);
        dog.addObserver(person);
        cat.addObserver(mouse);
        cat.addObserver(person);

        dog.bark();
    }

}

        运行结果:


其他说明

        关于抽象类Subject与接口Observer,在java.util包中已经有对应的类。其中这里的Subject(可扩展的被观察者职责类)对应util包下的Observable类,该类提供了线程同步的实现。这里的Observer(观察者接口)对应util包下的Observer接口,两个接口内的方法并没有多大区别。