设计模式—观察者模式

    科技2024-06-29  71

    设计模式—观察者模式

    什么是观察者模式观察者模式的实现

    什么是观察者模式

    观察者模式,是一种基于事件和响应的设计模式,常用于传统的窗体应用程序(触发鼠标点击事件等)以及游戏开发领域(触发陷阱事件等)。

    比如玩仙剑4的时候,点击“攻”按钮会发动普通攻击、点击“术”按钮会消耗神力发动法术、点击“技”按钮会消耗气力发动技能;在野外乱逛的时候,可能会遇到野怪进入战斗、也可能遇到宝箱获得宝物,还可能遇到存档点触发存档事件。

    这些都是不同的触发事件,也要求程序对其有不同的响应,传统的想法有:

    轮询:在程序中每隔一定事件查询事件是否发生,如果发生则进入对应的服务函数。但这种方法没有事件触发时程序在“空转”,会导致CPU使用率不高,且实时性不高;

    类成员:将所有事件设为操作者这个类的成员,出现操作时调用对应的成员对象的方法,相当于触发了事件响应。但这种写法在以后出现新事件时(新野怪、新宝箱等),必须要去修改操作者类,不具备低耦合性。

    这时我们就可以使用观察者模式。

    观察者模式主要有两组对象:一个是观察者对象(野怪、宝箱、存档点等),一个是被观察者对象(主角等):所有观察者都需要实现 Observer 接口;所有被观察者,都继承自 Subject 抽象类。

    Subject 类的成员 ObserverList ,存储已注册的观察者,当某个事件发生时,会通知列表中的所有观察者。

    观察者模式的实现

    我们这里使用 野怪、宝箱、存档点 的例子来展示观察者模式的Java实现:

    首先是写出观察者接口以及被观察者抽象类:

    public interface Observer{ //更新事件操作 public void update(); } abstract public class Subject{ //观察者列表 private List<Observer> observerList = new ArrayList<>(); //添加观察者 public void attachObserver(Observer observer){ observerList.add(observer); } //去除观察者 public void detachObserver(Observer observer){ observerList.remove(observer); } //观察者更新 public void notifyObserver(){ for(Observer observer:observerList){ observer.update(); } } }

    然后有多少种事件就定义多少个观察者类实现 Observer 接口:

    //野怪 public class Monster implements Observer{ @Override public void update(){ if(inRange()){ System.out.println("遭遇了怪物!"); } } private boolean inRange(){ //判断主角是否在野怪范围内 return true; } } //宝箱 public class Chest implements Observer{ @Override public void update(){ if(inRange()){ System.out.println("找到了宝箱!"); } } private boolean inRange(){ //判断主角是否在宝箱范围内 return true; } } //存档点 public class Archive implements Observer{ @Override public void update(){ if(inRange()){ System.out.println("到达了存档点!"); } } private boolean inRange(){ //判断主角是否在存档点范围内 return true; } }

    而主角类只需要继承 Subject 类,并定义他自身的一系列操作即可:

    //主角类 public class Hero extends Subject{ public void move(){ System.out.println("主角向前移动了一个距离"); notifyObserver(); } //还可以添加后退、攻击、跳跃等操作, //然后使用对应的方法对观察者列表进行触发即可 }

    测试函数:

    public static void main(String[] args) { //由于定义的类都是Observer_patterns的普通内部类 //所以需要创建一个Observer_patterns实例对象 Observer_patterns ob = new Observer_patterns(); //创建对应对象 Hero hero = ob.new Hero(); Monster monster = ob.new Monster(); Chest chest = ob.new Chest(); Archive archive = ob.new Archive(); //添加会触发事件的对象 hero.attachObserver(monster); hero.attachObserver(chest); hero.attachObserver(archive); //主角实例前进 hero.move(); }

    当然,对于全地图的怪物、宝物、存档点等观察者对象来说,不需要实时监测主角是否进入范围,换言之,在主角移动时,只需要将陈旧的不在附近的观察者对象移出观察者列表,并将附近新出现的观察者对象放入观察者列表即可。

    Processed: 0.011, SQL: 8