设计

所谓 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)即可。

至于可变参数的用法,可以参考下面两个文档:

  1. Variable-length output argument list
  2. Variable-length input argument list

优点

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 设计的更多相关文章

  1. [转] 阿里研究员谷朴:API 设计最佳实践的思考

    API是软件系统的核心,而软件系统的复杂度Complexity是大规模软件系统能否成功最重要的因素.但复杂度Complexity并非某一个单独的问题能完全败坏的,而是在系统设计尤其是API设计层面很多 ...

  2. API设计中防重放攻击

    HTTPS数据加密是否可以防止重放攻击? 否,加密可以有效防止明文数据被监听,但是却防止不了重放攻击. 防重放机制 我们在设计接口的时候,最怕一个接口被用户截取用于重放攻击.重放攻击是什么呢?就是把你 ...

  3. springMvc中restful风格的api路径中把小数点当参数,SpringMvc中url有小数点

    在springMvc web项目中restful风格的api路径中有小数点会被过滤后台拿不到最后一个小数点的问题, 有两种解决方案: 1:在api路径中加入:.+ @RequestMapping(&q ...

  4. API设计中性能提升的10种解决方法

    api的设计涉及到的方面很多, 分类是一个基本的思考方式.如果可以形成一个系列性的文字,那就从性能开始吧. 就像任何性能一样,API 性能主要取决于如何响应不同类型的请求.例如:典型的电商场景,显示用 ...

  5. javascript的api设计原则

    前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来.很难做到 ...

  6. Web API设计

    Web API设计经验与总结 在移动互联网的时代, Web服务已经成为了异构系统之间的互联与集成的主要手段,各种 Web服务几乎都采用REST风格的Web Api来构建. 通过Http协议的形式来. ...

  7. 架构师之路-在Dubbo中开发REST风格的远程调用

    架构师之路:从无到有搭建中小型互联网公司后台服务架构与运维架构 http://www.roncoo.com/course/view/ae1dbb70496349d3a8899b6c68f7d10b 概 ...

  8. 【Rest】在Dubbo中开发REST风格的远程调用(RESTful Remoting)

    目录 概述 REST的优点 应用场景 快速入门 标准Java REST API:JAX-RS简介 REST服务提供端详解 HTTP POST/GET的实现 Annotation放在接口类还是实现类 J ...

  9. 【JS】327- javascript 的 api 设计原则

    点击上方"前端自习课"关注,学习起来~ 前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博 ...

随机推荐

  1. 百度echars 插件 横坐标信息倾斜显示

    只需要 在xAxis   中加入 axisLabel:{                                  interval:0,//横轴信息全部显示                  ...

  2. JavaScript_AMD规范

    JavaScript_AMD规范 一.总结 一句话总结: Asynchronous Module Definition:AMD是"Asynchronous Module Definition ...

  3. MySQL 数据库 常用函数

    一.数学函数 数学函数主要用于处理数字,包括整型.浮点数等. ABS(x) 返回x的绝对值 SELECT ABS(-1) -- 返回1 CEIL(x),CEILING(x) 返回大于或等于x的最小整数 ...

  4. [Java]分解算术表达式一

    源码: package com.hy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputS ...

  5. windows+VS+Openjdk12 搭建debug环境

    openjdk12 下载地址: http://jdk.java.net/archive/ https://download.java.net/java/GA/jdk12/33/GPL/openjdk- ...

  6. leetcode 1两数之和

    使用哈希的方法:先将nums哈希表化,再遍历nums,寻找-nums[i]如果存在则为题目所求 class Solution { public: vector<int> twoSum(ve ...

  7. MutablePropertyValues的简单用法

    代码例子: package com.cy.model; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Get ...

  8. 十一:jinja2模板传参

    从后台传参到模板,模板再渲染到前端 传参的时候,可以在html后面加上关键字传参,在模板里面用{{ 参数 }}使用即可,可以传多个参数 也可以使用**传参,取值的时候就直接取内容

  9. LoadRunner 技巧之 检查点

    LoadRunner 技巧之 检查点 判断脚本是否执行成功是根据服务器返回的状态来确定的,如果服务器返回的HTTP状态为 200 OK ,那么VuGen 就认为脚本正确地运行了,并且是运行通过的.在绝 ...

  10. docker(常见调试技巧):docker打包镜像调试技巧

    写Dockerfile可以先不指定CMD.ENTRYPOINT等启动命令,只要拷贝就好了 如下: # Dockerfile for basic-app-client # Build with: # d ...