观察者模式--Observer

什么是观察者模式
1.生活中的观察者模式

老师(被观察者)在教室讲课(讲课理解为给学生发出信号),学生(观察者)要根据老师讲的内容做笔记(收到了老师的信号,开始记录)。这就是一个典型的观察者模式。

2.程序中的观察者模式

定义
观察者模式描述的是一种一对多的关系「一个被观察者对应多个观察者」,当被观察者的状态发生改变时,所有观察者都会得到通知。通俗的理解:观察者模式就是在特定的时刻「被观察者发送通知」干特定的事情「观察者收到通知处理自己相应的事件」

4239353708-5a2675bd3b566.png

结构

角色 类别 说明
Subject 接口或抽象类 主题也叫被观察者
RealSubject 真实的主题类 具体的被观察者,内部维护了观察者的列表
IObserver 观察者接口或抽象类 抽象出观察者的接口
RealObserver 具体的观察者 被观察者有更新,观察者立马响应更新
2322508216-5a2675bc42111.jpg
观察者模式应用
1.微信公众号推送文章

公众号为被观察者,用户为观察者,用户关注公众号(订阅事件),那么将会收到公众号文章的推送(发布消息)


3722694548-5a2675b91c83a.jpg

定义抽象的被观察者 IWxServerSubject.java

/**
 *
 * 定义主题「被观察者接口」,所有的公号作者共同属性「其实这里功能上微信系统的功能,直接抽象成被观察者」
 */
public interface IWxServerSubject {
    // 添加观察者
    void attchObserver(IObserver iObserver) ;
    // 移除观察者
    void detachObserver(IObserver iObserver) ;
    // 通知观察者
    void notifyObserver() ;
}

定义抽象的观察者接口 Observer.Java

/**
 *
 * 定义观察者接口,即关注公号的微信用户共同属性
 */
public interface Observer {
    // 观察者收到信息,内容为 info
    void reciveContent(String info) ;
}

定义具体的被观察者「公号作者 TigerChain」 TigerChainSubject.java

/**
 * 
 * 定义一个真实的被观察者 TigerChain「公号的作者」
 * 里面存了订阅 TigerChain 微信公众账号的读者
 */
public class TigerChainSubject implements IWxServerSubject {

    // 订阅者列表「观察者列表」,即关注 TigerChain 公号的读者
    private List<IObserver> observers = new ArrayList<>() ;
    //作者更新公号的内容 
    private String updateContent ;

    @Override
    public void attchObserver(IObserver iObserver) {
        observers.add(iObserver) ;
    }

    @Override
    public void detachObserver(IObserver iObserver) {
        if(observers.contains(iObserver)) {
            observers.remove(iObserver);
        }
    }

    @Override
    public void notifyObserver() {
        for (IObserver iObserver:observers) {
            iObserver.reciveContent(updateContent);
        }
    }

    /**
     * 是否关注我的公号
     * @param iObserver
     * @return
     */
    public boolean isAttchObserver(IObserver iObserver){
        return observers.contains(iObserver) ;
    }

    /**
     * TigerChain 在公号中发布文章
     * @param updateContent
     */
    public void submitContent(String updateContent){
        this.updateContent = updateContent ;
        this.notifyObserver();
    }
}

定义一个具体的观察者「普通的微信用户」 ReaderObserver.java

/**
 * 
 * 微信用户
 */
public class ReaderObserver implements Observer {

    // 微信用户的姓名
    private String name ;

    public ReaderObserver(String name){
        this.uname = name ;
    }

    @Override
    public void reciveContent(String info) {
        System.out.println(uname+"注意,TigerChain 发送了文章---"+info);
    }

    public String getUname(){
        return this.name ;
    }
}

接下来开始测试

/**
 *
 * 测试类
 */
public class Test {
    public static void main(String args[]){

        IWxServerSubject iWxServerSubject = new TigerChainSubject() ;
        // 微信用户
        ReaderObserver zhangsai = new ReaderObserver("张三") ;
        ReaderObserver lisi = new ReaderObserver("李四") ;
        ReaderObserver wangwu = new ReaderObserver("王五") ;
        ReaderObserver zhaoLiu = new ReaderObserver("赵六") ;

        // 微信用户张三关注我的公号「即订阅」
        iWxServerSubject.attchObserver(zhangsai);
        // 微信用户李四关注我的公号「即订阅」
        iWxServerSubject.attchObserver(lisi);
        // 微信用户王五关注我的公号「即订阅」
        iWxServerSubject.attchObserver(wangle);

        // 我「被观察者」发布了一篇文章--观察者模式
        ((TigerChainSubject)iWxServerSubject).submitContent("人人都会设计模式:观察者模式") ;

        boolean isAttch = ((TigerChainSubject)iWxServerSubject).isAttchObserver(zhaoLiu) ;
        if(!isAttch){
            System.out.println(zhaoLiu.getUname()+"你好!你还没有关注 TigerChain ,请关注先,谢谢");
        }
    }
}
2.狼王开会

狼是群居动物,由狼王带领。冬天来了,狼得找过冬的食物,狼王组织如开了紧急会议,下面的群狼都看着狼王传递会议精神和安排任务,此时狼王就是被观察者,群狼就是观察者。

3722694548-5a2675b91c83a.jpg

抽象被观察者功能

/**
 * 
 * 抽象的被观察者
 */
public interface Wolf {
    // 添加观察者
    void attchObserver(NormalWolf observer) ;
    // 移除观察者
    void detchObserver(NormalWolf observer) ;
    // 通知观察者
    void notifyObserver(String str) ;
}

抽象观察者普通的狼 NormalWolf.java

public abstract class NormalWolf {

    // 拿到被观察者的引用
    protected IWolf iWolf ;

    /**
     * 收到狼王下达的命令
     * @param str
     */
    public abstract void reciveCommand(String str) ;
}

定义具体的被观察者狼王 LangWang.java

/**
 * Created by TigerChain
 * 狼王「被观察者,下面的狼都看狼王的眼色行事」,是一个单例模式
 */
public class LangWang implements Wolf{

    private static LangWang instance ;
    private LangWang(){}
    public static LangWang getInstance(){
        if(instance == null){
            synchronized (LangWang.class){
                if(instance == null){
                    instance = new LangWang() ;
                }
            }
        }
        return instance ;
    }

    // 除过狼王外的狼「观察者」
    private List<NormalWolf> observers = new ArrayList<>() ;
    // 狼王下达的命令
    private String mingLing  ;

    @Override
    public void attchObserver(NormalWolf observer) {
        observers.add(observer);
    }

    @Override
    public void detchObserver(NormalWolf observer) {
        if(observers.contains(observer)){
            observers.remove(observer) ;
        }
    }

    @Override
    public void notifyObserver(String str) {
        for(NormalWolf observer:observers){
            observer.reciveCommand(str);
        }
    }

    /**
     * 下达命令
     * @param mingLing
     */
    public void xiaDaMingling(String mingLing){
        this.mingLing = mingLing ;
        this.notifyObserver(mingLing);
    }
}

定义一个观察者侦查狼 ZhenChaLang.java

/**
 * Created by TigerChain
 * 侦查狼,另一个观察者
 */
public class ZhenChaLang extends NormalWolf {

    public ZhenChaLang(IWolf iWolf){
        this.iWolf = iWolf ;
        this.iWolf.attchObserver(this);
    }

    @Override
    public void reciveCommand(String string) {
        System.out.println("侦查狼:狼王开会传递的信息是 \n"+string);
    }
}

定义另一个观察者捕猎狼 BuLieLang.java

/**
 *
 * 捕猎狼---观察者
 */
public class BuLieLang extends NormalWolf {

    public BuLieLang(IWolf iWolf){
        this.iWolf = iWolf ;
        // 添加观察者,即捕猎狼放在狼王组织中
        this.iWolf.attchObserver(this);
    }

    @Override
    public void reciveCommand(String string) {
        System.out.println("捕猎狼:狼王开会传递的信息是 \n"+string+"\n");
    }
}

测试

/**
 * 
 * 测试类
 */
public class Test {
    public static void main(String args[]){
        // 使用单例模式
        LangWang langWang = LangWang.getInstance() ;

        BuLieLang buLieLang = new BuLieLang(langWang) ;
        ZhenChaLang zhenChaLang = new ZhenChaLang(langWang) ;

        // 狼王下达命令就是发送通知
        langWang.xiaDaMingling("1、分工合作,捕猎狼根据侦查狼反馈看机行事 \n" +
                                     "2、侦查狼永远把危险放在第一位,遇到危险第一时间提醒大家撤退");

    }
}
观察者模式的优缺点

优点
1、解耦,被观察者只知道观察者列表「抽象接口」,被观察者不知道具体的观察者
2、被观察者发送通知,所有注册的观察者都会收到信息「可以实现广播机制」
缺点
1、如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时
2、观察者知道被观察者发送通知了,但是观察者不知道所观察的对象具体是如
何发生变化的
3、如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调
用,会导致系统崩溃

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

推荐阅读更多精彩内容