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 设计原则
点击上方"前端自习课"关注,学习起来~ 前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博 ...
随机推荐
- 可滚动UIStackView 竖向居中 / 横向右对齐
重点: 在scroll view和stack view之间加一个UIView. 竖向居中Tutorial: https://stackoverflow.com/questions/50766400/c ...
- 关于ArrayList的越界问题?
大家都知道 ArrayList是自动扩容的. 那为什么会存在越界问题? 话不多说 上代码 package test; import java.util.ArrayList; public class ...
- 两个 Activity 之间跳转时必然会执行的是哪几个方法?
一般情况下比如说有两个 activity,分别叫 A,B,当在 A 里面激活 B 组件的时候, A 会调用 onPause()方法,然后 B 调用 onCreate() ,onStart(), onR ...
- CSS 有序或者无序列表的前面的标记 list-style-type 属性
例子: <html> <head> <style type="text/css"> ul.none{list-style-type:none} ...
- Spliterator介绍
一.Spliterator Spliterator<T> trySplit();trySplit接口就相当于我们之前写的AccumulatorRecursiveTask类里面的分割任务,如 ...
- 阶段3 2.Spring_08.面向切面编程 AOP_4 spring基于XML的AOP-配置步骤
resources下新建bean.xml文件 xmlns:aop 先配置IOC aop 通知类就是logger.id配置为logAdvice表示日志的通知 梳理流程 首先我们在这有个Service它需 ...
- template要加s,重启服务,不然报错
- RabbitMQ问题解决
1.访问http://localhost:15672/#/,输入用户名.密码登录报错500 解决方法:在快捷程序处找到RabbitMQ Service -stop停止服务,然后再点击RabbitMQ ...
- delphi数组如何初始化
https://wenda.so.com/q/1535561587217078delphi数组如何初始化rosegirl09112级分类:其他被浏览44次2018.07.01检举满意答案 csx330 ...
- 工具栏对象GUI Status 与GUI Title
GUI Status 与GUI Title用于自定义工具栏按钮及Report程序标题栏显示内容, 可以通过se41\SE80或直接SE38中展开对象列表进行相关操作. 如下是在SE38里,点击[显示物 ...