引言:观察者模式——程序中的“通信兵”
在现代战争中,通信是胜利的关键。信息力以网络、数据、算法、算力等为底层支撑,在现代战争中不断推动感知、决策、指控等各环节产生量变与质变。在软件架构中,观察者模式扮演着类似的角色,它是确保信息在系统中高效、准确地流动的“通信兵”。
观察者模式确保了在软件系统中,当一个对象的状态发生变化时,所有依赖于这个状态的对象都能够及时得到通知。这种模式通过定义对象间的一对多依赖关系,使得一个对象的改变能够自动传播到其他对象。
观察者模式的概念
观察者模式是一种行为设计模式,它定义了对象间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合于实现分布式事件处理系统,如用户界面元素的响应、股票价格更新通知等。
为什么选择观察者模式?
降低耦合度:观察者模式通过定义对象间的依赖关系,降低了组件之间的耦合度,使得系统更加模块化。
提高系统的可扩展性:当需要增加新的观察者或被观察对象时,不需要修改现有的代码,只需遵循观察者模式的规则即可。
增强系统的灵活性:观察者模式允许对象在运行时动态地注册或注销观察者,使得系统能够灵活地响应变化。
本文的目的
在本文中,我们将深入探讨观察者模式的工作原理、实现方式以及如何在实际项目中应用它。
走近现实,聊聊军事下的“观察者模式”
观察者模式的角色构成
朱日和军演是中国每年举行的一次大规模军事演习,涉及多个部队和指挥中心。在这个例子中,我们可以将观察者模式应用到演习的指挥系统中。
主题(Subject):朱日和军演总指挥中心
- 总指挥中心负责制定演习计划,并维护一个观察者列表。
观察者(Observer):参演部队的指挥官或通信兵
- 参演部队的指挥官或通信兵希望在演习计划发生变化时能够收到通知。
具体主题(ConcreteSubject):具体的朱日和军演总指挥中心
- 具体的总指挥中心会在演习计划发生变化时通知所有观察者。
具体观察者(ConcreteObserver):具体的参演部队
- 具体的参演部队会在收到通知后,根据新的演习计划调整行动。
观察者模式的工作流程
注册: 各个参演部队向总指挥中心注册,表示自己希望收到演习计划的更新。
计划变更: 当总指挥中心制定了新的演习计划或现有计划发生变化时,计划变更被触发。
通知: 总指挥中心通知所有注册的参演部队,告知他们演习计划已经更新。
更新: 各个参演部队接收到通知后,根据新的演习计划调整自己的行动。
观察者模式的实现流程
下面,我将以朱日和军演的例子,将演习计划的变更通知到每一个参演部队,确保所有部队能够及时调整行动,协同作战。
第一步,新建一个主题接口,主要定义了注册、移除和通知观察者的方法。这是所有具体指挥中心必须实现的接口。
// 主题接口:军事指挥中心 public interface CommandCenter { // 注册观察者 void registerObserver(Observer observer); // 移除观察者 void removeObserver(Observer observer); // 通知所有注册的观察 void notifyObservers(String exercisePlan); }
第二步,新建一个观察者接口,其定义了一个更新方法,用于接收主题的通知。这是所有具体观察者必须实现的接口。
// 观察者:接收主题的通知 public interface Observer { void update(String message); }
第三步,创建具体主题类,实现了 CommandCenter 接口,负责管理观察者列表,并在演习计划改变时通知所有观察者。
// 具体主题类:朱日和指挥中心 public class ZhuRiHeCommandCenter implements CommandCenter { private List<Observer> observers = new ArrayList<>(); @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String exercisePlan) { observers.forEach(observer -> observer.update(exercisePlan)); } // 改变演习计划并通知观察者 public void changeExercisePlan(String newPlan) { notifyObservers(newPlan); } }
第四步,新建了一个TroopCommander 类, 实现了Observer 接口,负责接收演习计划的更新,并通知其下属的部队。
// 具体观察者:团长 public class TroopCommander implements Observer { private String name; private List<Troop> troops; public TroopCommander(String name) { this.name = name; this.troops = new ArrayList<>(); } public void addTroop(Troop troop) { troops.add(troop); } @Override public void update(String exercisePlan) { System.out.println(name + "收到指挥中心的命令:" + exercisePlan + "。并通知全体部队开始执行计划!"); for (Troop troop : troops) { troop.executePlan(exercisePlan); } } }
第五步,再次创建一个观察者,定义执行计划的方法,用于执行具体的演习计划。
// 观察者:执行具体的演习计划 public interface Troop { void executePlan(String plan); }
第六步,创建具体部队观察者,实现了 Troop 接口,负责执行具体的演习计划。
// 具体观察者:部队 public class CampTroop implements Troop { private String name; public CampTroop(String name) { this.name = name; } @Override public void executePlan(String plan) { System.out.println(name + "收到!执行计划:" + plan); } }
第七步,在客户端代码中使用观察者来执行朱日和军演指挥流程。
// 测试类 public class ZhuRiHeExerciseSystem { public static void main(String[] args) { ZhuRiHeCommandCenter commandCenter = new ZhuRiHeCommandCenter(); TroopCommander reedCommander = new TroopCommander("红军"); TroopCommander buleCommander = new TroopCommander("蓝军"); reedCommander.addTroop(new CampTroop("一营")); reedCommander.addTroop(new CampTroop("二营")); buleCommander.addTroop(new CampTroop("三营")); buleCommander.addTroop(new CampTroop("四营")); commandCenter.registerObserver(reedCommander); commandCenter.changeExercisePlan("执行方案A"); commandCenter.removeObserver(reedCommander); commandCenter.registerObserver(buleCommander); commandCenter.changeExercisePlan("执行方案B"); } }
从结果上看,利用观察者模式,红蓝双方都准备接收到了来自指挥中心传达的命令。