美文网首页
设计模式之三 观察者(Observer )

设计模式之三 观察者(Observer )

作者: 就爱烫卷发 | 来源:发表于2019-02-19 15:45 被阅读0次

    引言

    子曰:“温故而知新,可以为师矣。”(《为政》)

           近期看公司的项目的整个架构,发现各种回调,有的是走的接口,但是出现比较多的就是Observer ,感觉很熟悉,就是之前熟悉的观察者模式,于是又研究了一下。

    什么是观察者模式

           这个模式比较好理解,但是应用也非常多。这个文章写的比较好我这边就不继续介绍了,不理解的可以点开看看 https://www.cnblogs.com/luohanguo/p/7825656.html

    为什么用观察者

           两个字:解耦。对象之间的耦合越高,维护成本越高。说白了就是不要出现动一个地方的代码导致其他地方出现一大堆BUG的问题。

    个人理解

           其实要是搞设计一个整体的框架,那么观察者模式还是很好用的。当然这属于架构的搭建。主要是前期的设计。我们的MVP模式其实也有点观察者的意思,上面博客中那个notify()方法之后,他内部实现的就是

           for(int i = 0; i < list.size(); i++) {
               Observer oserver = list.get(i);
               oserver.update(message);
          }
    

           这里的oserver.update(message),我们跳开观察者模式来看 是不是就是简单的调用了observer里面的一个方法。然后他在他的update()方法中进行了他所需要的操作。MVP中Activity中首先也是先绑定了Prestener,然后调用P层的内部方法,让他在内部进行操作,比如网络请求,比如数据处理,处理完毕之后再通过调用自己绑定的view,通知UI更新。其实刚开始看MVP也觉得一头水,多看了几遍就明白了其实很简单。附上鸿洋的MVP: https://blog.csdn.net/lmj623565791/article/details/46596109。也就是通知别人做一些操作,Android 中的Handler 也有这个意思,你有什么事情了发个handler 切换到主线程 然后开始执行。但是会耦合到一个Activity中。当然handler最主要的功能还是线程的切换。

    使用案例

           最近研究了一波RecyclerView发现它里面的Adapter 就是用的观察者模式。

               public void setAdapter(@Nullable RecyclerView.Adapter adapter) {
                    this.setLayoutFrozen(false);
                    this.setAdapterInternal(adapter, false, true);//下面看一下这个SetAdapterInternal()方法
                    this.processDataSetCompletelyChanged(false);
                    this.requestLayout();
              }  
    
              private void setAdapterInternal(@Nullable RecyclerView.Adapter adapter, 
                        boolean compatibleWithPrevious, boolean removeAndRecycleViews) {
                        if(this.mAdapter != null) {
                        this.mAdapter.unregisterAdapterDataObserver(this.mObserver);
                        this.mAdapter.onDetachedFromRecyclerView(this);
                  }
                //省去部分代码....
                      if(adapter != null) {
                          adapter.registerAdapterDataObserver(this.mObserver);
                          adapter.onAttachedToRecyclerView(this);
                        }
                  }
    

           以上的代码我们看一下首先是this.mAdapter.unregisterAdapterDataObserver(this.mObserver);解绑定一个Observer 然后下面又进行了Register。将之前的adapter 进行了解绑然后注册了现在这个传过来的Adapter。看一下这个Observer是怎么写的源码中定义了一下这个Observer , private final RecyclerView.RecyclerViewDataObserver mObserver;看一下我们的RecyclerViewDataObserver 这是一个内部类,继承了RecyclerView.AdapterDataObserver ,下面 贴一下两个源码就会发现跟上面那个博客中写的很相似。
           AdapterDataObserver

       public abstract static class AdapterDataObserver {
            public AdapterDataObserver() {
            }
              public void onChanged() {
              }
              public void onItemRangeChanged(int positionStart, int itemCount) {
              }
              public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
                  this.onItemRangeChanged(positionStart, itemCount);
              }
              public void onItemRangeInserted(int positionStart, int itemCount) {
              }
              public void onItemRangeRemoved(int positionStart, int itemCount) {
              }
              public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
              }
          }
    

    跟上面的博客中的Observer 类似,写出几个接口的方法,下面的 RecyclerViewDataObserver 就跟上面的User是一个意思。也是继续实现里面的内部方法。
           RecyclerViewDataObserver

    private class RecyclerViewDataObserver extends RecyclerView.AdapterDataObserver {
                  RecyclerViewDataObserver() {
        }
        public void onChanged() {
            RecyclerView.this.assertNotInLayoutOrScroll((String)null);
            RecyclerView.this.mState.mStructureChanged = true;
            RecyclerView.this.processDataSetCompletelyChanged(true);
            if(!RecyclerView.this.mAdapterHelper.hasPendingUpdates()) {
                RecyclerView.this.requestLayout();
            }
        }
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            RecyclerView.this.assertNotInLayoutOrScroll((String)null);
            if(RecyclerView.this.mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
                this.triggerUpdateProcessor();
            }
        }
        public void onItemRangeInserted(int positionStart, int itemCount) {
            RecyclerView.this.assertNotInLayoutOrScroll((String)null);
            if(RecyclerView.this.mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
                this.triggerUpdateProcessor();
            }
        }
       ......省去部分代码
        void triggerUpdateProcessor() {
            if(RecyclerView.POST_UPDATES_ON_ANIMATION && RecyclerView.this.mHasFixedSize && RecyclerView.this.mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, RecyclerView.this.mUpdateChildViewsRunnable);
            } else {
                RecyclerView.this.mAdapterUpdateDuringMeasure = true;
                RecyclerView.this.requestLayout();
            }
        }
    }
    

           触发这个接口的方法之后调用triggerUpdateProcessor方法。内部再调用 RecyclerView.this.requestLayout();进行绘制页面。在adapter中调用一下notifyItemRangeInserted(1,1);这个方法然后点进去看一下

      public final void notifyItemRangeInserted(int positionStart, int itemCount) {
             this.mObservable.notifyItemRangeInserted(positionStart, itemCount);
        }
    

           再看看这里到底做的什么 再点进去看看

     public void notifyItemRangeInserted(int positionStart, int itemCount) {
              for(int i = this.mObservers.size() - 1; i >= 0; --i) {
                ((RecyclerView.AdapterDataObserver)this.mObservers.get(i)).onItemRangeInserted(positionStart,itemCount);
        }
    

           千呼万唤始出来,终于看到了onItemRangeInserted这个方法,这个就是上面的方法了 然后调用triggerUpdateProcessor()再进行UI的重新绘制。这样就完成了一次操作。层层拨开之后发现这个就是一个观察者模式。我们重新来看一下流程:

    setAdapter中的观察者模式.png
           基本流程就是这样,等等,好像缺了什么,这边只有观察者,那么被观察者呢。我们注册的时候注册上去的都是观察者,我们再去看看代码。回到上面的流程图的第四步,看一下这个mObservables是什么

    private final RecyclerView.AdapterDataObservable mObservable = new RecyclerView.AdapterDataObservable();
    这边来了一个AdapterDataObservable又是什么,再进去看看。

       static class AdapterDataObservable extends Observable<RecyclerView.AdapterDataObserver> {
              AdapterDataObservable() {
            }
              public boolean hasObservers() {
                return !this.mObservers.isEmpty();
            }
         ......省了很多代码
        public void notifyItemRangeRemoved(int positionStart, int itemCount) {
            for(int i = this.mObservers.size() - 1; i >= 0; --i) {   
                ((RecyclerView.AdapterDataObserver)this.mObservers.get(i))  
               .onItemRangeRemoved(positionStart, itemCount);
            }
        }
    }
    

           方法在这里面这个就相当于上面博客中的WeChat,有动作之后他再去通知后面的观察者。那么我们再看一下流程图:

    RecycleView中的观察者模式.png
           这里RecycleView中的观察者模式就结束了。撒花。

    总结

           初看设计模式,原来这个模式是这样的,一个简单的demo跑一下完事,知其然不知其所以然,现在花时间看一下确实这些设计模式都非常的棒,代码看上去非常的整洁,耦合低,我们现在用的比较多的EventBus 就是很显然的一个观察者模式。 EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));发布事件之后那边就可以接收到。Android 中的广播其实也有这个意思。本文通过一个别人写的一个观察者模式的demo(不自己写是因为写出来都差不多,没必要浪费这个时间,上面那写的确实不错),再看一下源码中的一些代码,可以更好的理解一下这个设计模式,还有运用场景。知道原由之后看到一些项目的时候,就不会因为要不停的点进去看怎么操作而浪费时间了,直接看一下大的接口一下子就知道要做什么,下一步要找谁,可以节约不少阅读时间。

    相关文章

      网友评论

          本文标题:设计模式之三 观察者(Observer )

          本文链接:https://www.haomeiwen.com/subject/cvkieqtx.html