码迷,mamicode.com
首页 > 其他好文 > 详细

认识接口(Interface)设计

时间:2015-10-31 01:47:28      阅读:755      评论:0      收藏:0      [点我收藏+]

标签:android 主板模式 主動型接口


by 高煥堂


认识接口(Interface)设计



1.两种接口:主动型与被动型 

  就软件主板(MB)设计(开发)者而言,反向调用的接口(如<I>)能让主板获得主控权,所以又称为主动型接口或强势型接口。而正向调用的接口(如CI接口)则让子类或Client类获得主控权,所有(从主板视角而言)又称为被动型接口。

  无论是主动型或被动型接口都是主板的基类(或称为父类)所提供的,但是这两种接口对于子类(或Client类)的制约能力并不相同,主动型接口让基类具有强大的制约能力(所以称为强势接口),可以主导子类的结构和行为;而被动型接口则不能带给(主板的)基类任何制约或主导力量。因此,分辨主动型与被动型API的区别,是极为重要的能力。两者可藉由3个攸关的动词来区别之:

     1. 定义(Define)

     2. 实现(Implement)

     3. 调用(Invoke or Call)


   根据这3个角度,可将接口区分为「主动型」与「被动型」两种,如下表:

    技术分享


    兹举Android的IPC主板模式为例,这软件主板里就含有两种接口,如下图所示:     

    技术分享


   其中,Binder基类的具象函数transact()调用onTransact()抽象函数,就反向调用到子类myBinder的onTransact()函数了。关于onTransact()抽象函数:

l  定义于基类

l  实现于子类

l  让基类来调用子类的实现

l  所以,对基类而言,它属于主动型接口

 关于的transact()具象函数:

l  定义于基类

l  实现于基类

l  让其它Client类(别)来调用

l  所以,对基类而言,它属于被动型接口

 如下图所示:

    技术分享


1.2 说明两种API的制约力量

   所谓被动型接口就是,相对而言,基类处于被主导(Dominated)的地位,也就是说,被子类或其它Client类所主导了。如下图:  

    技术分享


 上述execute()函数所构成的CI接口,其制约力量强弱程度比率为:

    基类:子类  è  0.4 : 0.6

  再看看主动型的接口,相对而言,基类处于主导(Dominate)的地位,也就是说,基类主导了子类。例如,上述onTransact()函数所构成的<I>接口,其制约力量强弱程度比率为:  就软件主板(MB)设计(开发)者而言,反向调用的接口(如<I>)能让主板获得主控权,所以又称为主动型接口或强势型接口。而正向调用的接口(如CI接口)则让子类或Client类获得主控权,所有(从主板视角而言)又称为被动型接口。

    基类:子类  è  0.8 : 0.2

  就此接口而言,基类具有高度的制约力量可主导子类。将上述的比率,配到上图里的主板模式里。兹进一步说明如下:

  • Client调用主板的execute()具象函数,属于主板的被动型接口,主板的制约力量只有0.4(比率是0.4:0.6)。

  • 主板调用子类的onTransact()函数,属于框架的主动型接口,框架的制约力量有0.8(比率是0.8:0.2)。

  • 所以,整体上而言,主板拥有制高点(即主导性)。所以才称之为<主板>。

 

以上说明了主板的两种接口。其中的主动型接口是最为重要的,因为它是实践主板的主控权的关键所在。

 

1.3 演练:分辨主动型与被动型接口

1.3.1 演练(一)

    许多App开发者是基于Android提供的基类来撰写App子类,然后与基类结合起来编译(Compile)和连结(Link)成为可执行的App。如下图:

    技术分享


   在此图里可以看到,Android基类View定义了onDraw()函数,它是一个可覆写的(Overridable)函数。于是,你就可以撰写一个子类(如上图里的myView),并覆写onDraw()函数。在程序执行时,基类就能反向调用到子类的onDraw()函数了。


演练问题:关于上图的onDraw()函数,属于基类(View)的主动型接口? 还是被动型接口呢?

 

1.3.2 演练(二)

    相信你已经扮演过上述的传统角色了。现在,您可以试试转换到一个全新的角色,飞上枝头变凤凰了。也就是从原来的App开发者,转变成为主板开发者。这个新鲜的角色就是:开发自己的主板基类和接口。首先设计一个View的子类别,设其名称为 GraphView。虽然它是View的子类别,也覆写了onDraw()函数;但是它又提供了一个可覆写的函数:doDraw();可让应用子类来覆写之。如下图所示:

     技术分享


  上图里的GraphView基类定义了一个可覆写的doDraw()函数,它可画出背景图像。执行时,GraphView的onDraw()函数调用其doDraw()函数。由于子类覆写了doDraw()函数,所以onDraw()会转而调用BirdView子类的doDraw()函数。此时,子类的doDraw()可以先调用基类GraphView的doDraw()去先画出背景,然后返回BirdView的doDraw()函数绘出前景图像。在GraphView里,其doDraw()函数里含有指令来画背景,这就是所谓的「预设行为」,子类别的doDraw()函数只要调用它,就能画出背景了;这可以减轻子类别的负担。

  

练问题:关于上图的doDraw()函数,属于GraphView的主动型接口? 还是被动型接口呢?


1.3.3 演练(三)

   当然还可以设计出其它的结构,例如可以将上述的预设行为独立出来成为一个新的函数,如取名为drawBackgraound()函数。此时,doDraw()就变成一个抽象函数了。如下图所示:

技术分享

  

演练问题:关于上图的drawBackground()函数,属于GraphView2的主动型接口? 还是被动型接口呢?

 

1.3.4 演练(四)

   当然还可以设计出其它的结构,例如下图:

   技术分享


   在这个结构里,是由基类GraphView2的onDraw()先调用drawBackground()函数来画出背景图像,然后才调用其doDraw()抽象函数,就转而返像调用了子类别BirdView的onDraw()函数来画出前景图像。

 

演练问题:关于上图的doDraw()函数,属于GraphView2的主动型接口? 还是被动型接口呢?

 

1.3.5 演练(五)

当然还可以设计出其它的结构,例如下图:

     技术分享


   此结构是是由基类GraphView3的onDraw()先调用drawBackground()函数来画出背景图像,然后才调用IDraw接口的doDraw()抽象函数,就转而返像调用了子类别BirdDrawing的onDraw()函数来画出前景图像。  


演练问题:关于上图的IDraw接口(内含doDraw()函数),属于GraphView3的主动型接口? 还是被动型接口呢?

  

1.4 将设计落实为程序码

 在上一节里,我们说明了传统AP开发者的则职责就是设计应用子类别。于此,我们来复习一下传统的角色,实际从基类View衍生出一个应用子类:myView,并写出其程序码。接下来的本节里,我们将变换一个角色,从传统的AP开发者摇身一变而成为框架的设计者或开发者。于是,就必须自己来设计框架的基类和接口了。


l  设计架构图

这个程序的结构,就如下图所示:

  技术分享


  这个范例共含三层,其中包括:两层框架和一层AP。上层框架是Google所开发的,而第二层框架是我们所开发的。上层框架里的View基类会反向调用到GraphView的onDraw()函数,接着onDraw()先调用自己的drawBackground()函数去绘制背景图案(本范例是绘出空白背景),然后调用IDraw接口的doDraw()函数,汇出一只蓝色的精灵飞侠。如下图所示:


   技术分享

l  撰写程序码

    首先建立一个Android的项目,如下:

   技术分享

 

★ 撰写你的基类和接口

// GraphView.java

package Framework;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.view.View;

 

publicclass GraphView extends View{

    private IDraw fgDrawer;

       public GraphView(Context context) {

        super(context);

    }

    @Override

 protected void onDraw(Canvas canvas) {

           super.onDraw(canvas);

           this.drawBackground(canvas);

           fgDrawer.doDraw(canvas);

              }

    protected void drawBackground(Canvas canvas){

        canvas.drawColor(Color.WHITE);

              }

    public void setForegroundDrawer(IDraw fgd){

                          fgDrawer = fgd;

         }

}

 

// IDraw.java

package Framework;

import android.graphics.Canvas;

 

publicinterface IDraw {

   voiddoDraw(Canvas canvas);

}

  

 

★ 把基类和接口送人,协助别人去开发应用子类

// myDrawing.java

package com.misoo.pk001;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.RectF;

import Framework.IDraw;

 

public class myDrawing implements IDraw {

     private Paint paint;

     

    myDrawing()

 {  paint= new Paint(); }

    public void doDraw(Canvas canvas) {

        paint.setAntiAlias(true);

        RectF rectF = new RectF(80,110,180,180);

        paint.setColor(Color.BLUE);

        canvas.drawArc(rectF, 220, 180,true, paint);

         paint.setStrokeWidth(3);

         canvas.drawLine(135,120, 140, 75, paint);

         canvas.drawLine(160, 140, 210, 130, paint);

        paint.setColor(Color.WHITE);

        canvas.drawCircle(128, 125, 6, paint);

        canvas.drawCircle(162, 145, 6, paint);

    }

}

 

// myActivity.java

package com.misoo.pk001;

import Framework.GraphView;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.LinearLayout;

 

publicclass myActivity extends Activity implements OnClickListener {

    private GraphView mv = null;

    private Button ibtn;

   

    @Override 

     protected void onCreate(Bundle icicle) {

        super.onCreate(icicle);

        LinearLayout layout = new LinearLayout(this);

        layout.setOrientation(LinearLayout.VERTICAL);

        mv = new GraphView(this);

        LinearLayout.LayoutParams param =

         new LinearLayout.LayoutParams(250, 280);

        param.topMargin = 10;    

    param.leftMargin = 10;

        layout.addView(mv,param);

        //----------------------------------------------

        ibtn= new Button(this);  

    ibtn.setOnClickListener(this);

        ibtn.setText("Exit");    

    ibtn.setBackgroundResource(R.drawable.gray);

        LinearLayout.LayoutParams param1 =

              new LinearLayout.LayoutParams(100, 65);

        param1.topMargin = 10;

       param1.leftMargin = 10;

        layout.addView(ibtn,param1);

        setContentView(layout);

        //-----------------------------------------------

         mv.setForegroundDrawer(new myDrawing());

    }

    public void onClick(View v)

{  finish();  }

}

 

~ End ~

 


认识接口(Interface)设计

标签:android 主板模式 主動型接口

原文地址:http://8204129.blog.51cto.com/8194129/1708189

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!