设计模式 观察者模式

从现实事例讲观察者模式


前言:观察者模式 = 观察者 + 主题


我们先看一个微信公众号的例子。

微信公众号
如上图所示,服务号就是我们的主题,使用者就是观察者。现在我们明确下功能:

1、服务号就是主题,业务就是推送消息

2、观察者只需要订阅主题,只要有新的消息就会送来

3、当不想要此主题消息时,取消订阅

4、只要服务号还在,就会一直有人订阅


观察者模式 = 观察者 + 主题:

  • 为什么这样说呢?我们来看下观察者定义。

    观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。
    这里写图片描述

    • 上述定义中发生互动的只有观察者对象主题对象,因此观察者模式等于他们两个组合相加。

实现主题和观察者

类图:

这里写图片描述
接下来实现这个类图,包括箭头的意思。


主题 interface,只要实现了 Subject 接口就能成为主题对象

    public interface Subject {

    //注册观察者,即订阅
    public void registerObserver(Observer o);

    //移除观察者,即取消关注
    public void removeObserver(Observer o);

    //主题状态改变,告诉观察者
    public void notifyObservers();
    }

主题者对象

  public class OneSubject implements Subject {

        //实现主题对象 ‘一对多’ 功能,即用容器管理所有订阅者。 
        private ArrayList observers;

        //数据状态。当然可以有多个。这是是为了行文方便
        private Object object;

       //判断是否这个改变是否需要通知观察者。
        private Boolean changed;


         //初始化容器
        public OneSubject() {
            observers = new ArrayList();
        }


        public void registerObserver(Observer o) {
            observers.add(o);
        }

        public void removeObserver(Observer o) {
           int i = observers.indexOf(o);
                if (i >= 0) {
                    observers.remove(i);
                }
        }

       //遍历观察者容器,将改变的数据传给每个观察者。
        public void notifyObservers(Object object) {
           if(changed){
              for (int i = 0; i < observers.size(); i++) {
                Observer observer = (Observer)observers.get(i);
                observer.update(OneSubject.this, object);
             }
                changed=false;
            }
        }

      //一旦状态改变,这个方法会被调用
      public void measurementsChanged() {
         //判断是否满足条件。比如送奶站‘早上’等等。满足才通知观察者
           if(condition){
                setChanged();
                notifyObservers();
            }
        }

     //暴露给外部,用来改变主题状态
      public void setMeasurements(Object object) {
            this.object=object;
            measurementsChanged(object);
        }

      //暴露给观察者获得数据
      public Object getObject(){
            return this.object;
        }

        //重要!!! 此方法有三个意义,可以先看第一条。其余可以返看。
        //1.筛选有效通知。只有有效通知可以调用 setChanged。比如微信公众号虽然有人一直在写文章,但只有在写好才发表,而不是发表一个未完成的草稿。

        //2.便于撤销通知操作,在主题中,我们可以设置很多次 setChanged,但是在最后由于某种原因需要取消通知,我们可以使用 clearChanged 轻松解决问题。

        //3.主动权控制,由于 setChanged 为 protected,而 notifyObservers 方法为 public,这就导致存在外部随意调用 notifyObservers 的可能,但是外部无法调用 setChanged,因此真正的控制权应该在主题这里。
         protected synchronized void setChanged() {
                 changed = true;
         }


  }

观察者 interface。只要实现了 Observer 接口就能成为观察者对象。

    public interface Observer {
        public void update(Subject subject);
    }

观察者对象实现

  public class OneObserver implements Observer  {
            private Object object;

  //初始化一个观察者时同时在主题中注册。
  //保存保存一个主题对象的引用方便以后取消注册
  public OneObserver(Subject subject) {
        subject.registerObserver(this);
  }

   //接受主题作为参数。根据不同主题更新响应数据。
  //现实意义是:小明可以同时向送奶站订牛奶,也可以关注女主播。。。。
   public void update(Subject subject) {
        //判断是哪个主题。根据主题来调用具体方法。
         if (subject instanceof OneSubject) {
            OneSubject OneSubject = (OneSubject)subject;
            object = OneSubject.getObject();
         }
   }

观察者模式有什么好处?

  • 松耦合
    • 观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。
    • 主题只负责通知观察者,但无需了解观察者如何处理通知。举个例子,送奶站只负责送递牛奶,不关心客户是喝掉还是洗脸。
    • 观察者只需等待主题通知,无需观察主题相关的细节。还是那个例子,客户只需关心送奶站送到牛奶,不关心牛奶由哪个快递人员,使用何种交通工具送达。
  • 方便客户端获取最新数据。客户端不必开一个线程时刻等待服务端改变数据。

收获:

  • 需要花时间去设计一类事物通用的接口。
  • 多用组合。观察者 + 主题。。
  • 对日常例子的抽象。目前来看观察者模式可以用生活例子来解释。那么其他模式呢?拭目以待哈哈哈**
  • 积累了博客排版的经验。排版累死了。CSDN的Markdown编辑器能上传图片真是太好了,作业部落。。

参考资料:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值