认识接口(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 ~
转载于:https://blog.51cto.com/8204129/1708189
认识接口(Interface)设计相关推荐
- (20)System Verilog接口interface设计示例
(20)System Verilog接口interface设计示例 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog接口interfac ...
- Go 学习笔记(35)— Go 接口 interface (接口声明、接口初始化、接口方法调用、接口运算、类型断言、类型查询、空接口)
1. 接口概念 接口是双方约定的一种合作协议.接口实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节.接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式.类型及结构. 接口内部存 ...
- 谈谈Java接口Result设计
这篇文章酝酿了很久,一直想写,却一直觉得似乎要讲的东西有点杂,又不是很容易讲清楚,又怕争议的地方很多,就一拖再拖.但是,每次看到不少遇到跟这个设计相关导致的问题,又忍不住跟人讨论,但又很难一次说清楚, ...
- 面向对象之内置方法(简单)、组合。以及接口归一化设计与抽象类
一.内置方法 一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo( ...
- Java接口(interface)的概念及使用
在抽象类中,可以包含一个或多个抽象方法:但在接口(interface)中,所有的方法必须都是抽象的,不能有方法体,它比抽象类更加"抽象". 接口使用 interface 关键字来声 ...
- java 抽象接口类,Java接口(interface)和Java抽象类(abstract class)的区别(详诉版)
1.概述 一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架, 当代表业务逻辑的高层抽象层结构合理时,你底层的具体实现需要考虑的就仅仅是一些算法 ...
- 组件接口(API)设计指南-文件夹
组件接口(API)设计指南-文件夹 组件接口(API)设计指南[1]-要考虑的问题 组件接口(API)设计指南[2]-类接口(class interface) 组件接口(API)设计指南[3]-托付( ...
- [转载]PSCAD调用MATLAB/SIMULINK之接口元件设计
原文地址:PSCAD调用MATLAB/SIMULINK之接口元件设计作者:luckyhappier 1)接口元件 接口元件包括Graphics,Parameters和Script.注意:变量要与DSD ...
- 分布领域驱动设计(DDD):领域接口化设计式缓存的选择
- 前言 - 把服务对象(service)和资源库对象(repository)设计成接口是最常见的.但是这对接口化的认识还远远不够,我们需要更深入地去分析接口化设计和更全面地应用接口化编 ...
- 开发日记:接口开发设计
接口开发使用规则 业务术语: 请求:通过HTTP协议把需要传输的数据发送给接收方的过程. 返回:根据得到的数据处理完成后,将处理完成的结果反馈给接收方. 敏感词:带有敏感政治倾向,暴力倾向,不健康色彩 ...
最新文章
- cacti监控linux和windows磁盘IO
- 5GS 协议栈 — PFCP 协议 — MAR 多接入规则
- 如何查找cvpr类的论文_如何查找期刊论文?(3个实用的方法)
- SD-SD用到的文本对象列表
- h5页面禁止复制_网页禁止鼠标右键禁止全选复制粘贴的方法
- linux内核安装教程,Linux内核5.9的最重要功能及安装方法
- 外媒:苹果已有条件批准京东方为iPhone 13供应OLED屏幕
- recvfrom函数 非阻塞_那些年让你迷惑的阻塞、非阻塞、异步、同步
- 《C专家编程》阅读笔记
- 如何利用手机的OCR文字识别功能制作扫描件?
- QQ这个版本已经绝版。
- HM-A300小程序安卓打印异常
- OpenJudge百炼习题解答(C++)--题4108:羚羊数量-Number Of Antelope
- Unity - 九宫格切图报错
- linux usb gadget驱动详解(一)
- 66W真的比60W充电更快吗?基于Charge pump Charger的快充方案分析
- 在线配资的诀窍是什么?
- 为Ubuntu安装Realtek的无线网卡驱动
- Python3.6 车牌识别代码源码
- 侠探锦毛鼠之真假白玉堂