认识接口(Interface)设计

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 ~

时间: 2024-10-13 13:15:56

认识接口(Interface)设计的相关文章

JAVA之旅(七)——final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展

JAVA之旅(七)--final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展 OK,我们继续学习JAVA,美滋滋的 一.final 我们来聊聊final这个关键字 final可以修饰类,方法和变量 final修饰的类不可以被继承 final修饰的方法不可以被覆盖 final修饰的变量是一个常量,只能被赋值一次 内部类只能访问被final修饰的局部变量 final,故名思意,就是最终的意思,由以上的五种特性,不过final的出现,也是有

C++里的接口(Interface)

C++是允许多重继承的,而这个设计既会引起问题又不是很常用,于是java和C#都采用了另一种方式:接口(Interface).类继承(实现)接口并不表明 is-a关系,而是“有某种功能”.“符合某种性质”的关系.C++虽然语法上不支持接口,但是这个思路还是可以拿来用的嘛.比如设计这样一个接口: struct hashable { virtual size_t hash_code() = 0; }; 然后让一个类继承它,并实现函数,就代表了该类是可哈希的. 事情没这么简单,在C++里,接口还可以有

聊聊高并发(三十九)解析java.util.concurrent各个组件(十五) 理解ExecutorService接口的设计

上一篇讲了Executor接口的设计,目的是将任务的运行和任务的提交解耦.能够隐藏任务的运行策略.这篇说说ExecutorService接口.它扩展了Executor接口,对Executor的生命周期进行管理.并进行了进一步的扩展. Executor负责执行任务. 它的生命周期有3个:执行,关闭和已终止. 在执行的不论什么时刻,有些 任务可能已经完毕,有些可能正在执行,有些可能正在队列中等待执行.所以假设要关闭Executor的话.就有多种方式,比方优雅平滑的关闭,当执行关闭时就不在接受新的任务

开发日记:接口开发设计

接口开发使用规则 业务术语: 请求:通过HTTP协议把需要传输的数据发送给接收方的过程. 返回:根据得到的数据处理完成后,将处理完成的结果反馈给接收方. 敏感词:带有敏感政治倾向,暴力倾向,不健康色彩或不文明的词. 特殊字符:特殊字符包括:^ | $ # 等. 操作结果:成功失败,成功返回结果,失败返回结果错误信息. 操作流程:执行之前,执行之后,正在执行. 接口编写规则: 1. 所有的接口必须包含method和version参数. 2. 所有的接口增加了版本号管理,以便适应多个不同版本客户端的

组件接口(API)设计指南-目录

组件接口(API)设计指南-目录 组件接口(API)设计指南[1]-要考虑的问题 组件接口(API)设计指南[2]-类接口(class interface)  (排版中,待续) 组件接口(API)设计指南[3]-委托(delegate)和数据源协议(data-source protocols)  (排版中,待续) 组件接口(API)设计指南[4]-通知(Notifications)  (排版中,待续) 组件接口(API)设计指南[5]-最后的思考  (排版中,待续) 快速摘要: 译者注: 原文中

组件接口(API)设计指南-文件夹

组件接口(API)设计指南-文件夹 组件接口(API)设计指南[1]-要考虑的问题 组件接口(API)设计指南[2]-类接口(class interface) 组件接口(API)设计指南[3]-托付(delegate)和数据源协议(data-source protocols) 组件接口(API)设计指南[4]-通知(Notifications) 组件接口(API)设计指南[5]-最后的思考 高速摘要: 译者注: 原文中"delegate"译为中文"托付/代理",含义

delphi 接口Interface

学习 delphi 接口 一切都是纸老虎!!! 第四章          接口 前不久,有位搞软件的朋友给我出了个谜语.谜面是“相亲”,让我猜一软件术语.我大约想了一分钟,猜 出谜底是“面向对象”.我觉得挺有趣,灵机一动想了一个谜语回敬他.谜面是“吻”,也让他猜一软件术 语.一分钟之后,他风趣地说:“你在面向你美丽的对象时,当然忍不住要和她接口!”.我们同时哈哈大 笑起来.谈笑间,似乎我们与自己的程序之间的感情又深了一层.对我们来说,软件就是生活. 第一节  接口的概念 “接口”一词的含义太广泛

C#编程利器之三:接口(Interface)【转】

C#编程利器之三:接口(Interface) C#接口是一个让很多初学者容易迷糊的东西,用起来好象很简单,定义接口,然后在里面定义方法,通过继承与他的子类来完成具体的实现.但没有真正认识接口的作用的时候就觉得用接口是多此一举,当然你这样想是绝对错误的.在软件设计中有一个非常重要的原则就是:面向接口编程,依赖与接口或抽象层.可见接口在真正的开发中是多么的重要. 在之前C#编程利器之一:类(Class)一文里介绍了类的相关知识,本文主要介绍OO编程中的另一个重要知识点--接口.在某种程度上说,接口也

好程序员训练营-Java接口(interface)的概念及使用

<A href="http://www.goodprogrammer.org/" target="blank">android培训</a>------我的java笔记,期待与您交流! 在抽象类中,可以包含一个或多个抽象方法:但在接口(interface)中,所有的方法必须都是抽象的,不能有方法体,它比抽象类更加"抽象". 接口使用 interface 关键字来声明,可以看做是一种特殊的抽象类,可以指定一个类必须做什么,而不