观察者模式属于行为设计模式,也叫发布订阅模式,在实际场景中应用很多,比如邮件订阅,微信公众号订阅等
观察者模式模板
观察者模式中需要两个角色,分别是观察者和被观察者,他们两个的叫法也有很多,如生产者和消费者,发布者和订阅者,发布者和监听者,但本质都是一样的
下面给出观察者模式的具体代码
被观察者接口,定义了一系列操作观察者的方法,以及他的实现类
// 被观察者接口
public interface Observable{
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver(Message message);
}
// 被观察者实现类
public class ObservableImpl implements Observable{
private List<Observer> list = new ArrayList<>();
void registerObserver(Observer observer){
list.add(observer);
}
void removeObserver(Observer observer){
list.remove(observer);
}
void notifyObservers(String message){
list.foreach(item -> item.doSomeThing(message));
}
void doThings(){
System.out.println("被观察者做事情了");
this.notifyObservers();
}
}
观察者接口,以及实现类
// 观察者接口
public interface Observer{
void handle(String message);
}
// 观察者1
public class Observer1 implements Observer{
void handle(String message){
// 观察者1的逻辑
System.out.println(message);
}
}
// 观察者2
public class Observer2 implements Observer{
void handle(String message){
// 观察者2的逻辑
System.out.println(message);
}
}
最后测试
// 测试
public class Demo{
public static void main(String[] args){
// 创建订阅者
Observer observer1 = new Observer1();
Observer observer2 = new Observer2();
// 注册订阅者
Observable observable = new ObservableImpl();
observable.registerObserver(observer1);
observable.registerObserver(observer2);
// 发布通知
observable.notifyObservers(new Message);
}
}
jdk 自带观察者模式接口
细心的人应该可以发现,被观察者职责并不单一,它既要处理自己的逻辑,又要有注册、删除、通知观察者的逻辑,应该抽象出一个父类,只处理被观察者的职责,而被观察者只需关心自己的逻辑,幸运的是,jdk 中已经有现成的被观察者父类, Observable ,并且还提供了观察者的接口 Observer ,接下来用 jdk 提供的父类和接口来实现一下观察者模式
想必大家对间谍一定不会陌生,在战争时期,间谍可以探查敌人的情报,知道敌人正在干什么,并作出相应的决策,接下来模拟的场景就是基于这个。
战国时期,韩非子和李斯处在不同的国家,立场不同,李斯想灭掉韩国,于是向韩非子身边安插了间谍,韩非子做什么,间谍都能及时的发现,报告给李斯,而李斯知道了韩非子正在干什么,就会报告给秦始皇,这里面,韩非子就是被观察者,而李斯则是观察者
首先创建人这个接口,因为韩非子也是人,他也和普通人一样要吃喝拉撒
// 人接口
public interface Person {
void eat();
void play();
}
接下来要创建韩非子这个人,并且他是被观察者,需要实现 jdk 提供的 Observable 接口
public class HanFeiZi extends Observable implements Person {
@Override
public void eat() {
System.out.println("韩非子:开始吃饭了");
super.setChanged();
super.notifyObservers("韩非子在吃饭");
}
@Override
public void play() {
System.out.println("韩非子:开始打游戏了");
super.setChanged();
super.notifyObservers("韩非子在打游戏");
}
}
然后就是实现李斯这个观察者了,观察者实现的是 Observer 接口,他里面就定义了一个 update 方法,对间谍发过来的信息进行处理
public class LiSi implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("李斯:观察到韩非子活动,开始向老板汇报...");
System.out.println("李斯:报告秦老板," + arg);
System.out.println("李斯:报告完毕");
}
}
这里 update 方法还有一个参数 Observable 接口没有使用到,这个参数实际上就是 HanFeiZi 这个对象,只有它是被观察者,可以通过这个对象来添加观察者或者删除观察者操作,这里暂时用不到
当然,事实上,想要消灭韩非子的肯定不止一个人,这里就不一一实现了
最后就是进行测试了
public class Main {
public static void main(String[] args) {
HanFeiZi hanFeiZi = new HanFeiZi();
LiSi liSi = new LiSi();
hanFeiZi.addObserver(liSi);
hanFeiZi.eat();
hanFeiZi.play();
}
}
结果
韩非子:开始吃饭了
李斯:观察到韩非子活动,开始向老板汇报...
李斯:报告秦老板,韩非子在吃饭
李斯:报告完毕
韩非子:开始打游戏了
李斯:观察到韩非子活动,开始向老板汇报...
李斯:报告秦老板,韩非子在打游戏
李斯:报告完毕
观察者模式注意事项
异步处理问题
**
被观察者作出动作,就要通知所有观察者,等一个观察者处理完后才能通知另一个观察者,如果某个观察者处理较慢,会拖累整个系统的运行速度。因此,最好的解决方案是用异步来处理观察者的逻辑,很多类似观察者模式的框架都是用异步的方式来实现的,如 Kafka