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

互联网全栈架构

共 2908字,需浏览 6分钟

 · 2020-07-11

ec471825fcd070b62bf69a4390879e4f.webp

d65dd326937dd50a17b6e989b1477965.webp



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

99ab95547d69974b81af84f38e112d77.webp

4bd7bedb44cded6160e52e4663322f2c.webp

2c0e3174f08709b66d837a87c113f056.webp

f6ebd679a61d9e0eeca22e667c30ab49.webp

35973493732255e87db81c095804a357.webp

3577f957f798259aa8d7761670bd81c8.webp

e85b243c7cd622f8dd2d154695abc7af.webp



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

dbc4e4e7578b6fdfb14fe147e60a80e5.webp

7554e97005a3147322b6d59c828e739d.webp

7d49f279e2f8b85251259918449ad8e9.webp

78c91e085eaaf8e896b9c9efedba85b2.webp

53770fc787152f23ed6cf057d21c85dd.webp


1a3a1264807a7d9ea18b3ea81f66cd62.webp

465a765bdc0b9979d2a218198c11868a.webp



场景1:游戏操作界面


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

f6986387ae94a9f72c130b791bb468cb.webp


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


d10b31a4950cdd23a38bcdbf1aecd5ca.webp


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



场景2:游戏迷宫


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


b2561dd18ee3a562d4e2c78b9fc1fe9a.webp


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


46eafdf9e1061e0bc42e5f4bfe8d0332.webp


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

72e0b74f1dad18f30b2bf5aebac04ad7.webp

eb36f714b55a5ccce644a35033f77bd7.webp


fe2b5049f8444ee41473c005931cb147.webp


32edbc8f92abe7d973c0ff37a0ae3a99.webp


c498f6900974e647c6f640fc75df9be8.webp


1eb4b9b382c68f2c17dfa339ca398e0d.webp

624c762052740c56a4f020c7ba58bb0a.webp


8095774e1b9ef9494fe730dff0f2968a.webp

3cecbd576e1a4f09a8468d7f6a7cdb6b.webp


public class Hero {
    //怪物
    Monster monster;
    //陷阱
    Trap trap;
    //宝物
    Treasure treasure;

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


57b5047f6f65a50d068b4c6fcfc1da6b.webp

367d3e8abb85d08be913482f97f2d27f.webp

1317c73fe6a28600da494b2c5d520c99.webp

ae5fa7dc09ad16c8ee04b007621c9af3.webp


3fb529821099d974a754f120c6730126.webp


603d54cf38f50f27446f485c6b4e404c.webp

d8fc5906ffc5c570944e9f911647f029.webp

44217ea5a408c35145327bcb589283c2.webp


292d1420d0a21546a4c5d7c644e04d3f.webp


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


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

743f07cb012f6858a010cebf6068d4c4.webp

89a4808f60ca73ddb448f7796f4ac883.webp


//观察者
public interface Observer {
    public void update();
}

//被观察者
abstract public class Subject {

    private List observerList = new ArrayList();

    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();
        }
    }
}


c6caa8ac6e07912d385ed4b98512e2e5.webp

//怪物
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方法,这是事件触发的回调方法,包含了具体观察者对事件的不同反应。


5804ae4c6fe8b08b423cdf40988f0944.webp


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


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

3458a2d4cc22044459c0d1df49dbd5f2.webp


public class Client {

    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();
    }
}


代码输出如下:


主角向前移动

怪物 对主角攻击!

陷阱 困住主角!

宝物 为主角加血!


52299251fed2713eeb53c3c8183946e6.webp


bdfe3d0af8e34b70008a91b2e2a1cf25.webp


6a7468b924b3bf2cb48e0b0778268b03.webp

9c33f12c0ef0de5f463773d76d1bfe5e.webp



c907b3cd61a90320c926d1fe5b4ef020.webp

1. 人人都能看懂的 6 种限流实现方案!

2. 一个空格引发的“惨案“

3大型网站架构演化发展历程

4Java语言“坑爹”排行榜TOP 10

5. 我是一个Java类(附带精彩吐槽)

6. 看完这篇Redis缓存三大问题,保你能和面试官互扯

7. 程序员必知的 89 个操作系统核心概念

8. 深入理解 MySQL:快速学会分析SQL执行效率

9. API 接口设计规范

10. Spring Boot 面试,一个问题就干趴下了!



8d52aa1da799b8f43823499292bb15c1.webp

扫码二维码关注我


·end·

—如果本文有帮助,请分享到朋友圈吧—

我们一起愉快的玩耍!



0435e3d44117e0d135c8c5c6eb052a04.webp你点的每个赞,我都认真当成了喜欢
浏览 3
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报