菜鸟成长系列-观察者模式

最近想深刻研究下响应式编程,做为基础颇有必要来把观察者模式撸一遍;一开始我是以为很easy,而后就直接开撸了,撸着撸着发现撸不动了。由于我忽然不太明白这个模式了,说好的观察者,到底发布-订阅的二者执行者谁才是观察者?又或者说还有其余角色?可是根据《JAVA与模式》一书中的结构,并无额外的角色出现。java

思考中....,好吧想不出来....,跑步去...编程

跑步时我给本身罗列了几个问题:后端

这里先抛出定义:GOF给观察者模式以下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新。设计模式

  • 既然是对象状态发生变动,那么究竟是谁的状态发生了变动,又致使了谁被通知。
  • 观察者模式既然又能够称之为“发布-订阅模式”,那么对应起来,观察者到底承当了“发布”的角色仍是“订阅”的角色。就是说观察者究竟是主动的仍是被动的?
  • 被观察者又干了什么事?它是主动的仍是被动的角色?

这里因为一些定式思惟,总会以为既然是“被观察者”,那么这个“被”字就是否是就代表“被观察者”是被动接受变动的一方,也就是接受通知的一方呢?微信

以前我也是走到这个胡同里了,程序写完总以为哪里不对;回过头看,仍是本身太年轻,没有get到哪些大佬们的点。app

先来看程序;这里用掘金来打个比方,个人博客glmmaper做为被观察者,也就是发布者。掘金小伙伴们做为观察者,也就是订阅者。ide

具体逻辑:小伙伴们(订阅者)关注(订阅)了个人博客(发布者),若是我发布了一篇文章(状态变动),就会通知(推送消息)全部关注个人小伙伴。spa

package com.glmapper.designmode.observor;
/** * @description: 抽象主题接口 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public interface Subject {
    /** * 新增关注者 * @param observer 关注的小伙伴 */
    void addFocusObserver(Observer observer);

    /** * 取消关注 * @param observer 取消关注的小伙伴 */
    void removeFocusObserver(Observer observer);

    /** * 通知机制,通知机制由相关事件来触发,好比说发布文章 * @param blogName 博客名 * @param articleName 文章名 */
    void notifyObservers(String blogName,String articleName);
}
复制代码

三个方法,一个是博客主页增长了一个关注者;一个是博客主页有小伙伴取消的关注(对于博客来讲就是移除一个关注者,这里不知道是否也会以为别扭?明明你取消的关注,为啥说成是我移除你,也就是不让你关注了,还能这么玩?这里确定是须要在引入其余的一些辅助机制,好比说你在客户端发起了一个取消关注的请求,后端处理的时候掘金的工程师们就是在个人关注列表中将你移除的,嗯,这么一想确实是我不让你关注了。😄....);最后一个方法是发起一个通知。下面是一个具体的博客,好比说是glmapper;设计

package com.glmapper.designmode.observor;

import java.util.ArrayList;
import java.util.List;

/** * @description: 这个是具体发布者,这里比喻成个人博客glmapper * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class ConcreteSubject implements Subject {
    /** 个人当前关注列表 */
    List<Observer> Observers = new ArrayList<>();
    /** 个人博客名 :求关注 */
    private static final String blogName = "glmapper";

    @Override
    public void addFocusObserver(Observer observer) {
        Observers.add(observer);
    }

    @Override
    public void removeFocusObserver(Observer observer) {
        Observers.remove(observer);
    }

    @Override
    public void notifyObservers(String blogName,String articleName) {
        for (Observer observer:Observers) {
            observer.update(blogName,articleName);
        }
    }
    
    /** * 这里是发布文章,触发通知事件 */
    public void publishArticle(String articleName){
        notifyObservers(blogName,articleName);
    }
}

复制代码

前面提到,通知事件确定是因为某些状态发生变动了,才会进行通知,这里就能够比方为我发布了一篇博客,而后通知你(这里只能假如你关注了)。再来看观察者:code

package com.glmapper.designmode.observor;

/** * @description: 订阅者抽象接口 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public interface Observer {
    /** * 调用此方法会更新状态,作出相应的动做 * @param blogName * @param articleName */
    void update(String blogName,String articleName);
}
复制代码

抽象订阅者,有一个update方法,通知你去作出相应的动做,具体动做每一个观察者均可能不一样。

package com.glmapper.designmode.observor;

/** * @description: 这个是具体订阅者,这里能够比喻成博客关注者, * 收到变动信息以后须要作出相应的动做 * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class ConcreteObserver implements Observer {

    @Override
    public void update(String blogName,String articleName) {
        System.out.println(blogName+"发布了新的文章,文章名为:"+articleName);
        read(articleName);
    }

    private void read(String articleName){
        System.out.println("即将阅读 "+articleName+" 这篇文章");
    }
}
复制代码

上面是一个具体的关注者,加入说就是你。博客更新以后发了一个通知给你(掘金app推送的消息),而后你点了一下,这个也是一种动做。例子中举的是read,就是关注者作出阅读的动做。

看下最后的运行结果:

package com.glmapper.designmode.observor;

/** * @description: [描述文本] * @email: <a href="glmapper_2018@163.com"></a> * @author: 磊叔 * @date: 18/4/22 */
public class MyMainIndex{

    public static void main(String[] args) {
        //博客主体
        ConcreteSubject subject = new ConcreteSubject();
        //关注者:handSome是帅气的意思
        Observer handSome = new ConcreteObserver();
        //增长一个关注者
        subject.addFocusObserver(handSome);
        //发一篇文章
        subject.publishArticle("设计模式-观察者模式");
    }

}


glmapper发布了新的文章,文章名为:设计模式-观察者模式
即将阅读 设计模式-观察者模式 这篇文章
复制代码

酒桶说:啊,欢乐时光老是短暂的

因此做为积累,仍是须要将一些基本的概念来罗列一下的。

观察者模式类图

主要角色:

  • 抽象主题角色(Subject:主题角色将全部对观察者对象的引用保存在一个集合中,每一个主题能够有任意多个观察者。抽象主题提供了增长和删除等观察者对象的接口。
  • 抽象观察者角色(Observer):为全部的具体观察者定义一个接口,在观察的主题发生改变时更新本身。
  • 具体主题角色(ConcreteSubject)(1个):存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给全部登记过的观察者发出通知。具体主题角色一般用一个具体子类实现。
  • 具体观察者角色(ConcretedObserver)(多个):存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。

具体关系:

  • 抽象主题(Subject)(接口)-->被具体主题(ConcreteSubject)角色(1个)实现

  • 抽象观察者(Observer)(接口)-->被具体观察者(ConcretedObserver)角色(N个)实现

  • 观察者对象载入主题方法,并在主题方法中调用观察者对象实现的接口方法update来让本身发生变动响应。

一些场景:

  • 当对一个对象的的改动会引起其余对象的变更时,并且你没法预测有多少个对象须要被改动。
  • 当一个对象须要有能力通知其余对象,且不须要了解这些对象是什么类型时。

基于发布订阅的具体实现例子仍是不少的,比较典型的就是这种订阅一个博客,而后博客更新推送;还有微信公众号,服务号这些。

到这里咱们再回过头来看一开始留下的几个问题:

  • 被观察者的状态发生变动,而后“主动通知”观察者,并非说,观察者主动去获取通知。
  • 被观察者是消息发布者,观察者是消息订阅者;观察者是被动接受者。
  • 被观察者的做用就是存储当前的观察者列表,而后提供一些通知机制来告诉观察者本身发生了状态变动,是主动者。

OK,观察者模式就撸到这里,也欢迎小伙伴们提出本身珍贵的意见;有写的不当之处烦请及时提出。

播报:菜鸟成长系列又开始更新了....

相关文章
相关标签/搜索