浅谈API设计
为什么需要了解一些API设计?
只要你编程,你就是API Designer
一个好的设计,模块之间的耦合应该也是API级别的
一个程序,如果你独立开发,那你既是API的Designer,也是API的User
如果你和你的同事一起开发,,你既是你开发的模块API的Designer,也是其他同事模块API的User
一个好的API应该具备哪些特点?
1. 易学易用(Easy to learn and use)
要做到易学易用,需要满足以下基本要求:
a. API命名的要适应用户的习惯并遵循一些模式。例如:使用类似于add/delete, get/set,push_bach/pop_back这种大家比较熟悉的命名方法。避免用户使用get获取一个数据,但是需要使用insert插入数据。
b. API的设计需要尽量简化用户的使用复杂度,我们看下STL vector的使用,非常简洁!
// vector::push_back
#include <iostream>
#include <vector> int main ()
{
std::vector<int> myvector;
int myint; std::cout << "Please enter some integers (enter 0 to end):\n"; do {
std::cin >> myint;
myvector.push_back (myint);
} while (myint); std::cout << "myvector stores " << int(myvector.size()) << " numbers.\n"; return 0;
}
c.尽量提供一些方便用户的api方法
例如提供一个STL vector提供at方法供用户获取指定位置的元素
reference at (size_type n);
但同时也提供API供用户直接获取第一个和最后一个元素
reference front();
reference back();
2. 引导用户写出可读性高的代码(Leads to readable code)
好的API设计,可以引导用户写出高可读性的代码,下面这个例子非常生动:
实现 1:
slider = new QSlider(8, 128, 1, 6, Qt::Vertical, 0,
"volume");
实现 2:
slider = new QSlider(Qt::Vertical);
slider->setRange(8, 128);
slider->setValue(6);
slider->setObjectName("volume");
显然第二种设计更易引导用户写出可读性高的代码
3. 很难被误用
一个好的API设计,会使用户很容易写出正确的代码,而不是错误的代码。
这点非常重要,如果你的API很容易用错,那么,一方面用户会吐槽,另一方面,API的维护成本也很高
so,当你收到很多错误报告的时候,不要抱怨用户的使用方法有问题,review下自己的API,是不是很容易被误用
4. 方便扩展(Easy to extend)
api会变的越来越“大”,未来,api会提供新的类,类中会有新的方法,方法会有新的参数,枚举数据也会有新的枚举值。
因此,在API设计过程中,需要时刻提醒自己保证API的可扩展性
5. 完整(Complete)
所谓的完整,并不是指API满足用户所有的功能需求,而是说,基于这些API,可以满足所有功能需求。
我们还是拿STL::Vector来做说明,从获取数据的角度,API提供了reference at (size_type n); 就是完整的,另外提供的front back都是方便用户获取数据,用户完全可以个性化实现这样的功能。但是,如果只提供了front、back,而没有提供at这样的api,就是不完整的
兼容性
在设计API时,非常重要的点是要提前考虑API的发布方式,在发布过程中,兼容性非常重要
我们可以将兼容性分为:源代码兼容,二进制兼容,功能兼容
在Deliver新版本的API时,需要明确告知用户,API版本在哪些层面做到了向后兼容
源代码向后兼容:老的程序,使用新的API库依然能够正常工作
二进制向后兼容:直接升级库文件,老的程序不必重新编译就能使用新的库文件
功能兼容向后兼容:老的程序,使用新的API库,不影响已有功能
功能兼容是业务的范畴,这里不展开。着重讨论下源代码兼容和二兼职兼容。一个很有意思的讨论Source compatible vs. Binary compatible
一般来说,二进制兼容是源代码兼容的子集。如果你的代码打破了源代码兼容,基本上可以肯定你也打破了二进制兼容。相反则不成立,一个API是源代码兼容但不是二进制兼容表示你的代码无需如何修改,只要重新编译程序即能正常工作。
我们看下c++来,什么情况下我们会满足源代码兼容,但不满足二进制兼容
c++发布api有静态和动态库两种方式,这两种发布方式各有优劣,当采取动态库的发布方式,就面临二进制兼容问题
c++通过头文件使用动态库,编译时也据此产生二进制代码,因此,在考虑动态库兼容性的时候,只要考虑库使用已有的头文件是否和新的动态库兼容
c++使用动态库最常见的二进制兼容问题就是使用虚函数作为接口产生的。c++虚函数通过虚函数表实现,虚函数表具有以下特点:
1)虚函数按照声明顺序放在表中
2)父类的虚函数放在子类的虚函数之前
so,如果我们在新版本的动态库中插入新的接口定义,由于虚函数的顺序,导致二进制兼容问题
即使你在你的接口中将新增虚函数放在最后,由于接口可能被继承,而父类的虚函数在子类虚函数之前,因此还是会导致二进制兼容性问题
为了解决这个问题,我们可以采用pimpl来解决!
有一篇非常棒的文章,C++ 工程实践(5):避免使用虚函数作为库的接口
一些API开发的建议:
1. 践行TDD
2. 如果可能,尽早和API使用方沟通
3. 重视命名,它比你想象的更重要
Reference:
Joshua Bloch:How to Design a Good API and Why it matters
Jasmin Blanchette Trolltech :The Little Manual of API Design
Kinds of Compatibility: Source, Binary, and Behavioral
浅谈API设计的更多相关文章
- [UWP]浅谈按钮设计
一时兴起想谈谈UWP按钮的设计. 按钮是UI中最重要的元素之一,可能也是用得最多的交互元素.好的按钮设计可以有效提高用户体验,构造让人眼前一亮的UI.而且按钮通常不会影响布局,小小的按钮无论怎么改也不 ...
- 浅谈API网关(API Gateway)如何承载API经济生态链
序言 API经济生态链已经在全球范围覆盖, 绝大多数企业都已经走在数字化转型的道路上,API成为企业连接业务的核心载体, 并产生巨大的盈利空间.快速增长的API规模以及调用量,使得企业IT在架构上.模 ...
- 浅谈UI设计中妙用无穷的深色系背景
英文:medium 译者:优设网 - 陈子木 链接:http://www.uisdc.com/ui-benefits-of-dark-background# --------------------- ...
- 浅谈API安全设计
一.简述 安全是恒久的话题,如果不注意防范,会带来很严重的后果.比如: 1.接口被大规模调用消耗系统资源,影响系统的正常访问,甚至系统瘫痪 2.数据泄露 3.伪造(篡改)数据,制造垃圾数据 4.App ...
- 开源项目 PM 浅谈如何设计官网
有用户反馈进入官网首页光秃秃的一片,大家忙着做产品,忽略了官网的建设,惭愧惭愧. 确实,极简风格和极其简单还是有很大区别的. 旧的 Web 端 除了极其简单之外,它还有一个小问题, ...
- 浅谈BUFF设计
Buff在游戏中无处不在,比如WOW.DOTA.LOL等等,这些精心设计的BUFF,让我们击节赞叹,沉迷其中. 问:BUFF的本质是什么? BUFF 是对一项或多项数据进行瞬间或持续作用的集合.(持续 ...
- Redis系列六 - 浅谈如何设计秒杀系统
前言 设计一个系统之前,我们肯定要先确认系统业务场景是怎样的,下面就以某电商平台上的秒杀活动为场景,一起来探讨一个秒杀系统改如何去设计. 场景 我们现在要卖100件纸尿布,按照系统的用户量及以往经验来 ...
- mybatis缓存源码分析之浅谈缓存设计
本文是关于mybatis缓存模块设计的读后感,关于缓存的思考,关于mybatis的缓存源码详细分析在另一篇文章:https://www.cnblogs.com/gmt-hao/p/12448896.h ...
- 浅谈API和SDK的区别
首先了解一下他们的定义 API:application program interface 应用程序接口 通常表示一些事先定义好的函数,为了向外部提供一组功能的实现,实现和其他软件的交互 SDK:so ...
随机推荐
- SQLServer,仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表xx中的标识列指定显式值
情景: 如果此表的主键或者其中有一个列使用了 IDENTITY(1,1) 自增长时,但又想手动为此列指定值时,当用如下解决方案: set identity_insert 表名 ON 使用此命令把表的 ...
- 网易云课堂_程序设计入门-C语言_第一周:简单的计算程序_1逆序的三位数
1 逆序的三位数(5分) 题目内容: 程序每次读入一个正三位数,然后输出逆序的数字.注意,当输入的数字含有结尾的0时,输出不应带有前导的0.比如输入700,输出应该是7. 输入格式: 每个测试是一个3 ...
- iOS中UITextView键盘回收
iOS开发中,发现UITextView没有像UITextField中textFieldShouldReturn:这样的方法,那么要实现UITextView关闭键盘,就必须使用其他的方法,下面是可以使用 ...
- html表格单元格设置背景颜色
- Egret及Node.js的安装部署
最近在学Html5游戏开发,我选择的是国内的一个游戏开发框架egret.因为涉及到node.js这个近年来新兴起来的技术.借此机会把这方面知识学习一下. node.js以及egret的操作类似于Lin ...
- OC中另外的一个常用技术:通知(Notification)
OC中另外的一个常用技术:通知(Nofitication)其实这里的通知和之前说到的KVO功能很想,也是用于监听操作的,但是和KVO不同的是,KVO只用来监听属性值的变化,这个发送监听的操作是系统控制 ...
- java.util.vector中的vector的详细用法
ArrayList会比Vector快,他是非同步的,如果设计涉及到多线程,还是用Vector比较好一些 import java.util.*; /** * 演示Vector的使用.包括Vector的创 ...
- Linux Mysql 总结
一:Error Code: . Access denied for user 'root'@'%' to database ① mysql -u root -p 进入到mysql中 ②SELECT h ...
- Linux网络管理——TCP/IP四层模型
1. 网络基础 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB",&q ...
- style-11bak
<resources> <style name="FullscreenTheme" parent="android:Theme.Holo"&g ...