Matlab 中 Data-driven 风格的 API 设计
设计
所谓 data-driven API,指的是用户可以把“操作”作为参数,传入函数,像下面这种:
stream = dataStream('load', 'example.csv');
image = dataStream('get', stream, 1);
newStream = processStream('map', @(im)(sobel(im)));
这是我最近在写的图像数据库读取的工具函数,我把视频或图片文件夹抽象成一个 dataStream,并基于这个 dataStream 完成一系列读写以及图像处理操作(processStream)。
代码中的 “load”(载入),“get”(读取),“map”(...就是你所知道的 map),都代表不同类型的操作,外层的 “dataStream”和 “processStream”仅起到一个入口的作用,它们的内部包含了每个操作的实现。设计 data-driven API 的方法很容易,例如上面的流处理函数:
function varargout = processStream(action, varargin)
varargout = repmat({[]}, [1 nargout]);
[varargout{:}] = feval(action, varargin{:});
end
function newstream = map(stream, action, varargin)
% ......map 的实现(略)
end
通过 varargin 和 varargout 传递可变的输入和输出参数,通过 feval 来调用对应的内部函数(例如map)即可。
至于可变参数的用法,可以参考下面两个文档:
优点
Data-driven API 解决了 Matlab 的一个缺点,即一个文件仅能放一个主函数(以及几个用户无法访问的辅助函数)。它使相同功能的函数被良好的组织到了一起,许多图像处理库都采用这种风格的设计。
脱离 Matlab 来看,Data-driven 使得开发者可以在不改变接口的情况下新增功能(例如,只要往 processStream.m 文件里加新的内部函数,就可以自动扩展 processStream 支持的操作);
此外, data-driven 还可以让 API 支持某种程度的 DSL,因为操作的类型是通过字符串描述的,那么我们可以把这些字符串组织成一个文本文件,通过读取并执行这个文件,就能让 API 执行你想要的功能,或者我们可以把所需执行的操作保存到一个数组里,让 API 读取并执行这个数组。
例如,基于 processStream,我设计了一个流水线操作的函数 pipeline.m:
% 像流水线一样处理数据:
% processStream('map',...) >>>> processStream('reduce',....)
% 操作按照 schema 来执行,schema 就像下面这个,是个嵌套的 cell array
% {
% { 'map' , 'sobel', [3, 3] }, % 先在流中运行 3x3 的 sobel 算子
% { 'map' , 'sharpen' }, % 在上一步的输出中运行锐化算子
% ..........
% }
% 这个 schema 相当于一个小的 DSL
function result = pipeline(stream, schema)
for i = 1 : numel(schema)
args = makeArguments(stream, schema{i});
result = processStream(args{:});
stream = result;
end
end
% 构造 processStream 的输入参数
function args = makeArguments(stream, operations)
args = {operations{1}, stream, operations{2:end}};
end
总结
我认为 Data-driven API 是 Matlab 中最重要的“设计模式”(如果它有设计模式的话...),通过它,我把图像数据库抽象成数据流,并在数据流上实现了 map, foreach,flatmap,reduce 等等一系列 functional 风格的操作,基于这些操作,我把一个原本很冗长的机器学习训练脚本变得十分简洁。
Matlab 中 Data-driven 风格的 API 设计的更多相关文章
- [转] 阿里研究员谷朴:API 设计最佳实践的思考
API是软件系统的核心,而软件系统的复杂度Complexity是大规模软件系统能否成功最重要的因素.但复杂度Complexity并非某一个单独的问题能完全败坏的,而是在系统设计尤其是API设计层面很多 ...
- API设计中防重放攻击
HTTPS数据加密是否可以防止重放攻击? 否,加密可以有效防止明文数据被监听,但是却防止不了重放攻击. 防重放机制 我们在设计接口的时候,最怕一个接口被用户截取用于重放攻击.重放攻击是什么呢?就是把你 ...
- springMvc中restful风格的api路径中把小数点当参数,SpringMvc中url有小数点
在springMvc web项目中restful风格的api路径中有小数点会被过滤后台拿不到最后一个小数点的问题, 有两种解决方案: 1:在api路径中加入:.+ @RequestMapping(&q ...
- API设计中性能提升的10种解决方法
api的设计涉及到的方面很多, 分类是一个基本的思考方式.如果可以形成一个系列性的文字,那就从性能开始吧. 就像任何性能一样,API 性能主要取决于如何响应不同类型的请求.例如:典型的电商场景,显示用 ...
- javascript的api设计原则
前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来.很难做到 ...
- Web API设计
Web API设计经验与总结 在移动互联网的时代, Web服务已经成为了异构系统之间的互联与集成的主要手段,各种 Web服务几乎都采用REST风格的Web Api来构建. 通过Http协议的形式来. ...
- 架构师之路-在Dubbo中开发REST风格的远程调用
架构师之路:从无到有搭建中小型互联网公司后台服务架构与运维架构 http://www.roncoo.com/course/view/ae1dbb70496349d3a8899b6c68f7d10b 概 ...
- 【Rest】在Dubbo中开发REST风格的远程调用(RESTful Remoting)
目录 概述 REST的优点 应用场景 快速入门 标准Java REST API:JAX-RS简介 REST服务提供端详解 HTTP POST/GET的实现 Annotation放在接口类还是实现类 J ...
- 【JS】327- javascript 的 api 设计原则
点击上方"前端自习课"关注,学习起来~ 前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博 ...
随机推荐
- spark MLlib 概念 2:Stratified sampling 层次抽样
定义: In statistical surveys, when subpopulations within an overall population vary, it is advantageou ...
- 一、基础篇--1.1Java基础-Object类中常见的方法,为什么wait notify会放在Object里边
这是个设计相关的问题,它考察的是面试者对现有系统和一些普遍存在但看起来不合理的事物的看法.回答这些问题的时候,你要说明为什么把这些方法放在Object类里是有意义的,还有不把它放在Thread类里的原 ...
- asp.net 获取服务器及客户端的相关信息
1. 在ASP.NET中专用属性:获取服务器电脑名:Page.Server.ManchineName获取用户信息:Page.User获取客户端电脑名:Page.Request.UserHostName ...
- IDEA常用智能提示
psvm: 生成代码: public static void main(String[] args) { }
- LDA(Latent Dirichlet Allocation)主题模型算法
原文 LDA整体流程 先定义一些字母的含义: 文档集合D,topic集合T D中每个文档d看作一个单词序列< w1,w2,...,wn >,wi表示第i个单词,设d有n个单词.(LDA里面 ...
- 浏览器端-W3School-HTML:HTML DOM Audio 对象
ylbtech-浏览器端-W3School-HTML:HTML DOM Audio 对象 1.返回顶部 1. HTML DOM Audio 对象 Audio 对象 Audio 对象是 HTML5 中的 ...
- Linux-ubuntu命令-文件、磁盘管理
.文件管理 <1>查看文件信息:ls ls是英文单词list的简写,其功能为列出目录的内容,是用户最常用的命令之一,它类似于DOS下的dir命令. Linux文件或者目录名称最长可以有26 ...
- 代码实现:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%; 利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提成7.5%; 20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%; 60万到100万之间时,高于60万元的部分,可提成1.5%,高于100万元时,超过100万元
import java.util.Scanner; /* 企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%: 利润高于10万元,低于20万元时,低于10万元的部分按10%提成 ...
- Netflix颠覆HR:我们只雇“成年人”
员工的最佳福利,是与优秀者一起工作 ● Patty McCord / 文 李钊/译 担任Netflix的首席人才官时,我与CEO里德·黑斯廷斯一起做了一份127页的PPT,命名为<自由& ...
- vue按需引入Element UI的方法
在我们的实际项目开发中,多数是采用按需引入的模式来进行开发的,那么具体应该如何操作呢,可能会有许多新人傻傻分不清楚,具体将在下文讲到. 首先我们先vue create demo创建一个项目出来此时我们 ...