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

最近想深入研究下响应式编程,作为基础很有必要来把观察者模式撸一遍;一开始我是觉得很easy,然后就直接开撸了,撸着撸着发现撸不动了。因为我突然不太明白这个模式了,说好的观察者,到底发布-订阅的两者执行者谁才是观察者?又或者说还有其他角色?但是根据《JAVA与模式》一书中的结构,并没有额外的角色出现。

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

跑步时我给自己罗列了几个问题:

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

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

这里由于一些定式思维,总会觉得既然是“被观察者”,那么这个“被”字就是不是就表明“被观察者”是被动接受变更的一方,也就是接受通知的一方呢?

之前我也是走到这个胡同里了,程序写完总觉得哪里不对;回过头看,还是自己太年轻,没有get到哪些大佬们的点。

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

具体逻辑:小伙伴们(订阅者)关注(订阅)了我的博客(发布者),如果我发布了一篇文章(状态变更),就会通知(推送消息)所有关注我的小伙伴。

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

复制代码

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

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,观察者模式就撸到这里,也欢迎小伙伴们提出自己珍贵的意见;有写的不当之处烦请及时提出。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值