观察者模式学习笔记(详细)

观察者模式学习笔记(详细)

一、什么是观察者模式

观察者模式,是定义对象之间的一对多的关系,主要作用是减少对象之间的耦合度,分为两个角色

  1. 被观察者:其实就是发布者,发布消息通知所有的观察者
  2. 观察者:接到被观察者发布的消息做出相应的动作

上图中,左边一组是被观察者,右边一组是观察者

  • Subjecct:被观察者抽象类,拥有类成员ObserverList,和三个抽象方法
    ObserverList:存放所有的观察者对象
    addObserver():向ObserverList中添加观察者对象
    delObject():从ObserverList中删除观察者对象
    notifyObservers():通知所有的观察者对象

  • SubjectItem:具体的被观察者类,继承Subject接口,有具体的动作方法,调用父类的notifyObject()方法通知所有的观察者

  • Observer:观察者接口,有一个抽象方法update(),供被观察者调用

  • ObserverItem:具体的观察者类,实现Observer类,实现update()方法

二、使用场景

游戏中,被观察者主角有所动作就通知观察者们
支付中,一个商品购买成功,需要执行许多操作(更新订单,发送邮件,更新账户...),这时就可以使用观察者模式来减少耦合
再比如,关注动态,动态更新,需要发送通知给所有的关注者

三、具体实现

简单的一个冒险游戏,勇者做为被观察者,观察者有怪物,食物,NPC
当勇者移动碰到怪物时血量减1,碰到食物时血量加1,碰到NPC时展开剧情

  1. 编写Observer接口
    public interface Observer {
        public void update();
    }
  1. 编写Subject抽象类
    public abstract class Subject {
        //观察者集合
        private List<Observer> observerList = new ArrayList<>();
                
        //添加观察者
        public void addObserver(Observer observer){
           observerList.add(observer);
        }
        
        //删除观察者
        public void delObserver(Observer observer){
            observerList.remove(observer);
        }
            
        //通知所有观察者
        public void notifyObservers(){
            for(Observer observer : observerList){
                observer.update();
            }
        }
        
    }

observerList集合存放了观察者接口,不直接存放观察者类
notifyObservers()方法遍历observerList集合,调用update()方法
通过抽象层减少耦合

  1. 编写勇者类(被观察者)
    public class Hero extends Subject {
    
        static int X = 0;
        static int Y = 0;
    
        //勇者移动
        public void move(int x, int y){
            X = x;
            Y = y;
            super.notifyObservers();
        }
    
    }

Hero类有move()方法,让勇者移动并调用父类的notifyObservers()方法通知所有的观察者

  1. 编写怪物类(观察者)
    public class Monster implements Observer {
    
        static int X = 5;
        static int Y = 7;
    
        @Override
        public void update() {
            if(Hero.X == X && Hero.Y == Y){
                System.out.println("怪物攻击勇者!");
            }
        }
        
    }  

Monster类实现Observer接口,实现具体的update()方法

  1. 编写食物类(观察者)
    public class Food implements Observer {
        
        static int X = 8;
        static int Y = 8;
    
        @Override
        public void update() {
            if(Hero.X == X && Hero.Y == Y){
                System.out.println("勇者吃到了食物,血量加1!");
            }
        }
        
    }  

Food类实现Observer接口,实现具体的update()方法

  1. 编写npc类(观察者)
    public class Npc implements Observer {
    
        static int X = 15;
        static int Y = 20;
    
        @Override
        public void update() {
            if(Hero.X == X && Hero.Y == Y){
                System.out.println("勇者遇到NPC,剧情展开!");
            }
        }
    
    }

Npc类实现Observer接口,实现具体的update()方法

  1. 编写执行类
    public class Run {
        
        public static void main(String[] args){
            //初始化对象
            Hero hero = new Hero();
            Monster monster = new Monster();
            Food food = new Food();
            Npc npc = new Npc();
    
            //添加观察者
            hero.addObserver(monster);
            hero.addObserver(food);
            hero.addObserver(npc);
            //勇者移动,遇到怪物
            hero.move(5,7);
            //勇者移动,吃到食物
            hero.move(8,8);
            //勇者移动,遇到npc
            hero.move(15,20);
        }
    
    }

勇者移动时通知了所有已注册的观察者,执行各自的update方法

  1. 运行结果

四、总结

  • 优点:
    使用抽象的方式来减少被观察者和观察者之间的耦合,可以方便的增加观察者

  • 缺点:
    如果被观察者有过多的直接观察者和间接观察者的话,会花费更多的时间,如果观察者之间存在循环依赖的话,会导致他们直接进行循环调用,最终导致系统崩溃
    观察者可以知道被观察者发生的变化,但是无法知道被观察者是如何发生的变化

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352