设计模式—观察者模式

设计模式—观察者模式

什么是观察者模式

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

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

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

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

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

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

观察者模式主要有两组对象:一个是观察者对象(野怪、宝箱、存档点等),一个是被观察者对象(主角等):所有观察者都需要实现 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();
}

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值