当前位置: 华文问答 > 动漫

漫画:什么是「观察者模式」?

2020-10-16动漫

————— 第二天 —————

————————————

场景1:游戏操作界面

在一个小游戏中,包含一个简单的操作界面,界面上有两个按钮:道具和魔法。

如果点击「道具」按钮,游戏里的主角会使用道具;如果点击「魔法」按钮,游戏里的主角会使用魔法。

如何让主角实时接收到点击按钮的事件,并做出相应的行动呢?

场景2:游戏迷宫

同样在这个小游戏里,有一个迷宫,迷宫里有怪物、陷阱和宝物。

一旦主角移动到怪物的有效范围,怪物会袭击主角;主角移动到陷阱的有效范围,陷阱会困住主角;主角移动到宝物的有效范围,宝物会为主角加血。

如何让主角移动的事件被怪物、陷阱、道具感知到,并做出正确的反应?

public class Hero { //怪物 Monster monster; //陷阱 Trap trap; //宝物 Treasure treasure; public void move(){ System.out.println("主角向前移动"); //主角移动时,分别通知怪物、陷阱和宝物对象 monster.update(); trap.update(); treasure.update(); } }

在上面的UML图中,主要有两组实体对象,一组是观察者,一组是被观察者。所有的观察者,都实现了Observer接口;所有的被观察者,都继承自Subject抽象类。

Subject类的成员OberverList,存储着已注册的观察者,当事件发生时,会通知列表中的所有观察者。需要注意的是,OberverList所依赖的是抽象的Observer接口,这样就避免了观察者与被观察者的紧耦合。

//观察者 public interface Observer { public void update(); } //被观察者 abstract public class Subject { private List<Observer> observerList = new ArrayList<Observer>(); public void attachObserver(Observer observer) { observerList.add(observer); } public void detachObserver(Observer observer){ observerList.remove(observer); } public void notifyObservers(){ for (Observer observer: observerList){ observer.update(); } } }

//怪物 public class Monster implements Observer { @Override public void update() { if(inRange()){ System.out.println("怪物 对主角攻击!"); } } private boolean inRange(){ //判断主角是否在自己的影响范围内,这里忽略细节,直接返回true return true; } } //陷阱 public class Trap implements Observer { @Override public void update() { if(inRange()){ System.out.println("陷阱 困住主角!"); } } private boolean inRange(){ //判断主角是否在自己的影响范围内,这里忽略细节,直接返回true return true; } } //宝物 public class Treasure implements Observer { @Override public void update() { if(inRange()){ System.out.println("宝物 为主角加血!"); } } private boolean inRange(){ //判断主角是否在自己的影响范围内,这里忽略细节,直接返回true return true; } }

上面代码中,每一个具体观察者类都实现了update方法,这是事件触发的回调方法,包含了具体观察者对事件的不同反应。

public class Hero extends Subject{ void move(){ System.out.println("主角向前移动"); notifyObservers(); } }


当主角移动时,通知所有已注册的观察者,执行具体观察者各自的update方法。

public static void main(String[] args) { //初始化对象 Hero hero = new Hero(); Monster monster = new Monster(); Trap trap = new Trap(); Treasure treasure = new Treasure(); //注册观察者 hero.attachObserver(monster); hero.attachObserver(trap); hero.attachObserver(treasure); //移动事件 hero.move(); } }

代码输出如下:

主角向前移动

怪物 对主角攻击!

陷阱 困住主角!

宝物 为主角加血!

推荐阅读:

还在使用if else写代码?试试 「策略模式」 吧!

喜欢本文的朋友们,欢迎长按下图关注公众号 程序员小灰 ,收看更多精彩内容