本篇博客将书写一个简单的观察者模式案例。
参考博客:https://blog.csdn.net/qq_33591903/article/details/97005268
什么是观察者模式?
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。这就是观察者模式。
被观察者发布信息,观察者收到信息,也可以说是订阅模式,发布者发布信息,订阅者获取信息。
接下来先用一个小案例说明场景,然后用代码实现。
案例场景:
在一个风和日丽,阳光明媚,万里无云,晴空万里(跑题了)的午后,主任躺在自家摇椅上休息打盹,忽然院子里的狗狗叫了一声,主人听到后去看下情况,猫也听到了并且被狗吓的尖叫起来,而由于猫的尖叫,躲在角落的老鼠瑟瑟发抖,然后一溜烟的溜了。主人看到猫被吓到了赶忙回来抱起猫咪安抚一下它的情绪。然后外面的狗子好像不乐意了又叫了一声,主人又去看了看。
这里的狗子属于被观察者,
猫既是观察者也是被观察者,猫观察狗,猫被老鼠观察
主人属于观察者,主人观察猫,狗
老鼠属于观察者,老鼠观察猫
代码示例
关系如下图
我们将被观察者的职责抽象成Subject,在这个类中,需要保存关注该被观察者的观察者集合,以及增加、删除观察者的方法,以及最重要的通知方法。任何被观察者都需要继承此类,这样只去考虑自己的逻辑方法即可。
/**
*
* @class: Subject
* @title: 被观察者的职责
* @desc: 被观察者的职责
* @author: zhoukaishun
* @date: 2019年7月24日 上午10:47:51
* @since: 1.0.0
*/
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
public void addObserver(Observer o){
observers.add(o);
}
public void removeObserver(Observer o){
observers.remove(o);
}
public void notifyObservers(){
observers.forEach(e->{
e.update(this);
});
}
}
将观察者的职责抽象成Observer接口,任何观察者都需要实现此接口。在该接口中,提供update方法,用于在接收到通知后,执行相应的处理方法。
/**
*
* @class: Observer
* @title: 观察者接口
* @desc: 观察者接口
* @author: zhoukaishun
* @date: 2019年7月24日 上午10:47:27
* @since: 1.0.0
*/
public interface Observer {
void update(Subject s);
}
实体类
/**
*
* @class: Dog
* @title: 狗子
* @desc: 狗仅是被观察者
* @author: zhoukaishun
* @date: 2019年7月24日 上午10:45:54
* @since: 1.0.0
*/
public class Dog extends Subject{
public void bark(){
System.out.println("狗叫");
super.notifyObservers();
}
}
/**
*
* @class: Cat
* @title: 猫咪
* @desc: 猫即是被观察者,也是观察者。猫被主人和老鼠观察,猫观察狗
* @author: zhoukaishun
* @date: 2019年7月24日 上午10:45:02
* @since: 1.0.0
*/
public class Cat extends Subject implements Observer{
@Override
public void update(Subject s) {
if(s instanceof Dog){
System.out.println("猫听到狗叫,吓了一跳,害怕的叫了起来");
scream();
}
}
private void scream() {
System.out.println("猫尖叫起来");
super.notifyObservers();
}
}
/**
*
* @class: Mouse
* @title: 老鼠
* @desc: 老鼠仅是观察者
* @author: PC
* @date: 2019年7月24日 上午10:46:28
* @since: 1.0.0
*/
public class Mouse implements Observer{
@Override
public void update(Subject s) {
if(s instanceof Cat){
System.out.println("老鼠听到猫叫,吓跑了");
}
}
}
/**
*
* @class: Person
* @title: 主人
* @desc: 主人仅是观察者
* @author: zhoukaishun
* @date: 2019年7月24日 上午10:46:53
* @since: 1.0.0
*/
public class Person implements Observer{
@Override
public void update(Subject s) {
if(s instanceof Dog){
System.out.println("主人听到狗叫,去看了看");
}else if(s instanceof Cat){
System.out.println("主人听到猫叫,去看了看");
}
}
}
测试
public class TestObserver {
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();
System.out.println("主人看到猫被吓到了,抱起来安抚一下");
System.out.println("------------相当于猫取消了订阅---------------");
dog.removeObserver(cat);
System.out.println("狗又叫了一声");
dog.bark();
}
}
运行结果
说明
关于抽象类Subject与接口Observer,在java.util包中已经有对应的类。其中这里的Subject(可扩展的被观察者职责类)对应util包下的Observable类,该类提供了线程同步的实现。这里的Observer(观察者接口)对应util包下的Observer接口,两个接口内的方法并没有多大区别。