Android 面向协议编程 体会优雅编程之旅

Android中面向协议编程的深入浅出

http://blog.csdn.net/sk719887916/article/details skay编写

说起协议,现实生活中大家第一感觉会想到规则或者约定,确实协议的本意就是一种约束,每个人事物都遵守的准则或法则,如果拿生活中的列子来说 法律本身就是一种协议 每个人自然人去遵守,只有遵守了这个法则,执行法律的法院才会对遵守的人管辖有效,当然前提是你必须是在某个国家的法律之内,如果不是某个法律的协议范围之内,当然法院的执法者是无法对其他国家的自然人进行管理的,也就需要一个中间的桥接者进行沟通,比如目前的大使馆就是做这种协议转换的作用。而大使馆又是一个更高层次的协议。

面向协议

那对于编程语言来说协议的范围可以有多方面的解释,不同的语言对协议也有着不同的定义,但是他们的最终目的还是和上面说到的现实问题相一致的,就拿java语言来说 协议是什么,在从事java开发多年的人也未必听说过协议,但说起规则,大家都会想到java接口,确实interface是约束某种规则的,我们定义了某个功能的一些方法,让其他功能遵守了这个协议(java是实现这个接口),才能正常的实用起功能。java对于协议编程有我们熟知的面向接口编程一说,这只是对协议编程的一种细化,java中的接口更是对一种具体api的运用的编程,那么这样的接口编程其实未必是一种行为的协议编程,为什么这么讲呢 我们可以看看OC的中的协议编程。

OC的运用是由于iOS移动开发的兴起而的到广泛运用,然后oc也是一种面向对象语言,也拥有java一样的oop思想,而只不过和我的java的接口有所不同,oc中用了协议一词,它让某个类去遵守某个协议,这样也许更确切显示生活中的协议,OC协议中没有抽象类一说,只有一个单纯的@protocol来进行声明,但是他的实现类并不是我们java中的接口实现类,这里要明确一点OC语言每个类都有一个声明类和实现类,而OC的对于协议的实现类我们要和OC本身的语法要进行区分对待,协议用关直接在继承类(NSObject)后面 <协议名>即可,他的协议也有必须实现和选择实现两种

  1. @required:表示必须强制实现的方法
  2. @optional:表示可以有选择性的实现方法

JAVA中用abstract 来定义我们的可选规则和不可选规则,而java中真正的接口类不如说是协议,还不如说他是oc中的代理,于是协议和代理其实密切关联的。

  1. 面向切面

    说完了协议的概念和在编程语言中的定义,大家会想到面向切面编程,也就是从上面提到的面向接口编程一样,会问到面向协议,面向接口,面向切面,面向对象有啥区别。今天你就以本人的见解给大家梳理一遍

  2. 面向对象

    面向对象是把任何东西看成一个基本单元,大的基本单元包含小的基本单元,就是把一个整体的东西做到细化,从而是实现整体的组装。

  3. 面向接口

    面向接口狭义的定义就是对java的接口API的完美运用,编程者建议我们都用接口实现功能重组,其实也是基于面向对象语言的一种特性的多态的扩展,其实这种采用注入方式,或者我们Java1.5新增的注解其实也是对于接口的延生,那么面向接口一般用在小规模的编程中,如果放到整个编程架构,那么面向接口还是去无法完美说服力

  4. 面向切面

    提到面向切面其实也是对于面向接口的总结,他是将代码现实化,如果我们说道面向接口,大家第一感官就会想到java类的接口类,并不关心一个现实生活中的具体代表什么,那么面向切面来了,他是将我的事物分成一个个事物单元和事物组件,那么这个组件就可以担负起桥接单元的功能,而这个组件有一定的约束力哦,只有符合该组件的要求才能由他来连接,那么通俗的将我们并不关系某个组件由什么组成,我们也只要知道这个单元是符合这个组件的越束就行,就类似我们所说的热插拔,插座和插头的功能,而这种广泛运用在服务端比较多,著名的spring就利用面向切面思想,依赖我们需要的配置注入,其实也就延生客户端的面向协议编程诞生。

    面向协议

    那么面向协议该怎么做解释呢,在我们的移动端的开发中,我觉得用面向协议总结上面123点的结合一起比较合适,面向协议并不是只是对具体API的运用,也不是对某种局部功能的拆分细化,更不是对某种方法的抽象,也不是说某个功能我们要去完成必须去写一个dao,用daoIPML(javaweb端的常用做法),而是将我的某种规则(某种功能)去和具体调用和分离,也和具体实施者做分离,不管我具体的由谁去做这个规则的实施,但是这个规则是存在,而具体调用规则的人也灵活的,那么移动端的面向协议方可这么认为。

安卓面向协议编程

通看安卓源码我们可以看到谷歌工程师喜欢用xxxManger, xxxMangerImpl,XXXRoot, BaseXXX, 自我分析很久,也许这只是他们的编程习惯而已,更有可能安卓只是一个移动端操作系统,而某些组件更是唯一一组功能集合的管理者,因此以管理者命名的原因居多。在这里暂且不管原因,我们看他实现的整个过程中,所有的组件都是在我们的ActivityThred(以下简称AT)去做动态注入的,也就是说不管是viewRootImpL, ActivtiyManferImpl,都是在AT做实现类的注入,如果某些Manager需要上层调用,那么他会将此Manager绑定到我们的Context静态类中,因此我们在很对地方拿到上下文,就可以得到某些Manager的原因,然后这些manager并不是具体的实现类,都是由他们的IMPL去完成,如果我去做重写或者覆盖东西,其实context内部也利用外部重载进来的代码进行实现,我们就拿普通的onClick()事件来说,比如我在某个界面中给某个view注入单击事件

mView.setOnClickListener("我们自己定义的OnClickListener实现类");

我么看过这个listener后他也就是个接口源码如下

/**
* Interface definition for a callback to be invoked when a view is clicked.
* */
 public interface OnClickListener {
/**
 * Called when a view has been clicked.
 *
 * @param v The view that was clicked.
 */
void onClick(View v);
}

看到他会把我们的listener加入到ListenerInfo中用来一个TAG将事件和view做绑定,

 public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
    setClickable(true);
}
getListenerInfo().mOnClickListener = l;

}

这些其中的事件传递就不在做些说,那么他由我们的最底层的viewrootImpl(activity的消费事件最终也有viewrootIMpl来进行原始的调用)来进行处理最后回调到我的下面方法

public boolean callOnClick() {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
    li.mOnClickListener.onClick(this);
    return true;
}
return false;

}

代码里的只是调用了OnClickListener的onClick()然后就会将我们代码实现的处理逻辑执行,这充分给我们的开发者有自我扩展的能力,不但不会影响源码的其他代码,而且还给了开发者有自己去实现的方式,这也只是一种面向协议的简单运用。

Mvp面向协议编程架构运用

mvp是一种架构模式,我们通常可以将安卓当中的视图和数据分离,采用presenter来进行管理,数据和模型是无法直接通信的,这和mvc的根本区别就是视图和模型无任何交集。

这里写图片描述

但是在庞大的安卓源码中可能并不是只是一个视图和数据模型的分离,也有可能是众多presenter的分离,这将会产生功能之间的mvp架构模式,rootPresener来管理众多的childPresenter, 那么这种面像协议的编程就来了 我们可以看看安卓某些某块的源码(ViewManger)

public interface ViewManager {

public void addView(View view, ViewGroup.LayoutParams params);

public void updateViewLayout(View view, ViewGroup.LayoutParams params);

public void removeView(View view)

}

其实也是一一个接口类我们的具体实现类如下ViewGroup去实现,看看其中的addView()的实现

 public void addView(View child, int index, LayoutParams params) {

   if (DBG) {
      System.out.println(this + " addView");
   }

  // addViewInner() will call child.requestLayout() when setting the new LayoutParams
  // therefore, we call requestLayout() on ourselves before, so that the child's   request
   // will be blocked at our level
   requestLayout();
   invalidate();
   addViewInner(child, index, params, false);

  }

但是具体的添加视图(addview)只是一个动作性方法,源码又提供了一个进行逻辑性的接口类(ViewParent) 源码部分:

  public interface ViewParent {

     public void requestLayout();

     public boolean isLayoutRequested();

     public void requestTransparentRegion(View child);

     public void invalidateChild(View child, Rect r);

     public ViewParent invalidateChildInParent(int[] location, Rect r);

     :::::::略

    public void bringChildToFront(View child);

    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);

    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
    boolean immediate)
  }

两个抽象的接口都是由viewgroup去实现,而viewgroup是在viewroot在启动activtiy时候帮到我们的acitivty的,一次一连串的功能协议就走通了,接下来我们可以想想这种思想的好处,为何不直接调用呢,

面向协议编程好处

  1. 增加扩展功能,也更容易保障具体实现类代码的安全
  2. 增加新的传参方式(代码块)
  3. 更容易实现低耦合的思想
  4. 将具体的实现者进行和执行者分离

这里说个题外话,谷歌喜欢视图层运用Root, Child, 逻辑用Base Normal, 核心开放类用Manager,一般便于维护。这些类是无法修改的。其实只是一种编程的习惯,这和java jdk的命名习惯有很大区别的。

上一篇:编程范式 --- 面向协议编程(Protocol Oriented Programming,简称POP)


下一篇:oracle查询第一篇