1.定义
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。
就是多个对象观察一个对象,如果被观察的对象发生改变,则依赖的对象也做出相对应的改变。
是一种行为型模式,主要是将观察者和被观察者解耦。
2.场景
1.用户注册后会发送一个站内消息或者会发送一个消费卷给用户。此时可以用观察者模式解耦用户注册逻辑和发送消息逻辑。如果后面需求还需要变更,只需将观察者去掉或者新增即可。
2.还有一种就是消息通知类型的,比如b站上面你关注了某些up主,如果up主更新动态时,你就会收到这条消息,如果不关注则不会收到概消息。
3.往架构层面上说,有点类似于MQ这种消息中间件,订阅和发布的模式。
3.案例
1.场景描述
在英雄联盟中,如果一个玩家被击杀,击杀的信息会被其他玩家收到。这个就有点类似于订阅和发布的模式。
2.代码实现
创建监听模式接口:
public interface EventListener {
void handleEvent(EventVo eventVo);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EventVo {
private String message;
}
创建监听者(玩家A,玩家B):
public class PlayerAListener implements EventListener{
@Override
public void handleEvent(EventVo eventVo) {
System.out.println("玩家A收到消息:"+eventVo.getMessage());
}
}
public class PlayerBListener implements EventListener{
@Override
public void handleEvent(EventVo eventVo) {
System.out.println("玩家B收到消息:"+eventVo.getMessage());
}
}
创建监听管理器:主要用于添加,删除监听,和发布消息。
public class EventManager {
private final List<EventListener> listeners;
public EventManager(){
listeners = new ArrayList<>();
}
/**
* 通知所有监听者
* @param event 事件消息
*/
public void notifyAll(EventVo event){
for (EventListener listener : listeners) {
listener.handleEvent(event);
}
}
public void addListener(EventListener listener){
listeners.add(listener);
}
public void removeListener(EventListener listener){
listeners.remove(listener);
}
}
模拟击杀逻辑:
public interface PlayerService {
void kill();
}
public class PlayerServiceImpl implements PlayerService{
private final EventManager eventManager;
public PlayerServiceImpl(){
eventManager = new EventManager();
//注册监听者
eventManager.addListener(new PlayerAListener());
eventManager.addListener(new PlayerBListener());
}
/**
* 击杀信息
*/
@Override
public void kill() {
EventVo eventVo = new EventVo("GayLun击杀Ez");
//击杀敌人
System.out.println(eventVo.getMessage());
//将消息通知给玩家A
//将消息通知给玩家B
eventManager.notifyAll(new EventVo());
}
}
3.测试结果
public class TestApi {
public static void main(String[] args) {
PlayerService playerService = new PlayerServiceImpl();
playerService.kill();
}
}
GayLun击杀Ez
玩家A收到消息:null
玩家B收到消息:null
4.拓展
1.相关框架
- spring框架提供的SpringEvent相关类,实现监听。
- Guava工具类中提供EventBus,用于发布/订阅模式的事件处理组件,也可以异步。
5.总结
观察者模式主要将核心逻辑和辅助逻辑解耦,而且易于扩展和变化。实现的方式不是那么重要,主要是知道其中的设计原则,代码只是实现其思想,可以有多种形式。
参考文章
重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」 | bugstack 虫洞栈