专栏首页程序员小灰漫画:设计模式中的 “观察者模式”

漫画:设计模式中的 “观察者模式”

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

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

场景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 class Client {

代码输出如下:

主角向前移动

怪物 对主角攻击!

陷阱 困住主角!

宝物 为主角加血!

本文分享自微信公众号 - 程序员小灰(chengxuyuanxiaohui),作者:小灰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 漫画:设计模式之 “外观模式”

    于是肯德基对这些菜品做了一定的组合,推出了各种各样的套餐。比如A套餐,包括汉堡/薯条/可乐;B套餐,包括汉堡/鸡翅/沙拉/可乐:

    小灰
  • 漫画:什么是 “小镇做题家” ?

    内卷化的大意是说:在某些特殊的局面当中,尽管每一个局内人都在努力争取自己的利益,但是这些人越是努力,造成的无谓损耗越大,大家的整体利益却没有得到提升。

    小灰
  • 用Java语言,写一个植物大战僵尸简易版!

    小灰的一位读者,用Java语言开发了自己的植物大战僵尸游戏。虽然系统相对简单,但是麻雀虽小五脏俱全,对游戏开发感兴趣的小伙伴可以学习一下哦~~

    小灰
  • [享学Netflix] 四、Apache Commons Configuration2.x定位FileLocator和FileHandler

    上一篇讲述了Commons Configuration2.x它全新的事件-监听基础,一方面体会到了相较于1.x的改动之大,另一方面也能感受到2.x在可扩展性方面...

    YourBatman
  • spring中的多线程aop方法拦截

    日常开发中,常用spring的aop机制来拦截方法,记点日志、执行结果、方法执行时间啥的,很是方便,比如下面这样:(以spring-boot项目为例)

    菩提树下的杨过
  • R语言Markowitz马克维茨投资组合理论分析和可视化

    实际上很难在该图上将重要的东西可视化:收益之间的相关性。它不是点(单变量,具有预期收益和标准差),而是有效边界。例如,这是我们的相关矩阵

    拓端
  • WCF系列教程之客户端异步调用服务

    本文参考自http://www.cnblogs.com/wangweimutou/p/4409227.html,纯属读书笔记,加深记忆 一、简介 在前面的随笔中...

    郑小超.
  • Spring - 通过注解配置Bean(8)

    特定组件包括: Component:基本注解,标识了一个受Spring管理的组件 Respository:标识持久层组件 Service: 标识服务层(业...

    桑鱼
  • 【ZOJ 1221】Risk

    饶文津
  • 归并排序

    将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(有序表),这种操作称为归并操作。这样的方法经常用于多个有序的数据文件归并成一个有序的数据文件。...

    attack

扫码关注云+社区

领取腾讯云代金券