观察者模式
定义
简而言之,观察者模式定义了对象间一种一对多的依赖关系,当某个对象发生状态的变化后,任何关注此对象的观察者会得到通知。观察者模式也成订阅/发布模型,当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接口,两个接口内的方法并没有多大区别。