您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
如何利用多级抽象思维来设计库?
 
作者 Tomas Petricek 来源:Tomas Petricek's blog  火龙果软件 发布于 2015-3-18
  1734  次浏览      29
 

开发者在设计库时,应遵循如下几大原则:迭代设计、可组合的、避免回调、抽象级别。此外,在你的库中,应该提供高级函数来帮助用户处理80%的任务。对于剩下的15%,应该提供一个低级API。

编者按:之前,我们曾发表《函数式语言库模式:框架是魔鬼?》该文论述了库与框架之间的区别,及如何设计组合化的库。而本文作者在此之前,还发表了一篇《Library patterns: Multiple levels of abstraction》,结合具体实例,向大家非常详细地介绍了库设计模式及库设计中的多级抽象思想。

以下为具体译文:

库设计模式

对于库设计理论来说,有几点在我的实际工作过程中体会最深:

  • 迭代设计——首先,不要为了一个库而设计库。在F#中,你可以把多个功能都放入一个脚本然后按需进行引用或复制至其它项目。这是最好的库需求分析途径。一旦你想出更好的点子,就可以把它以文件形式加入到一个新项目中;
  • 可组合的——可组合性是函数式编程的关键理论,其重要性等同于库设计。一个库应当可以让用户以简单的方式来进行二次开发,实现更多更复杂的功能;
  • 避免回调——回调是很容易影响可组合性的。当你编写一些复杂的函数时(例如处理Markdown文档),你可能会受到诱惑而进行参数化回调(例如置入一个预处理器来对文档进行解析和翻译间的转换)。回调的问题是会使你的代码被加上太多的结构。这不但不会带来灵活性,反而随着回调的增多而使设计变得更加复杂;
  • 抽象级别——那么我们怎么才能找到简单易用的API并在不同场合进行使用?问题的关键是能提供多级抽象。

我认为上述几点是最能影响库设计好坏的。本文将先就抽象级别一点展开论述。

库是如何被使用的?

每个库都对应着一定的典型应用场合。比方说,F# Formatting格式工具可以对一个目录下的所有文 件进行文档生成,这占到使用频率的80%。有时我们可能需要以不同的方式来处理个别文件(例如使用不同模板)。一个完整的库应能兼顾该需求。还有某些时候我们需要以别的方式来处理某个文件,如添加一个自动生成内容表(TOC)。

对于类似的情况,我找到一种行之有效的处理方法—以多级功能抽象的方式来创建库。在最高级,单一个函数调用应处理80%的应用场合。然后如果有需要,你可以再多建一级来处理额外15%的应用场合。最后如果还有需要,就再多建一级来处理最后4%的应用场合。对于最后的1%,我的建议是发送一个pull request!

该设计模式在核心功能库中是被深度采用的,例如F#链表库。遵循该模式,还能使我们的库成为领域的特定语言从而更具可读性。

示例#1:链表

用链表来阐述多级抽象是很有代表性的。

  • 高级:高频函数

在高级抽象,可以使用高频函数来对链表进行处理(或在C#中使用LINQ)。例如从0到100的整数中获取正的sin值链表,可以这样编写:

类似List.map和List.filter的高频函数在链接处理中有80%频率会用到甚至更高。但有时我们可能需要非高频操作。

  • 低级:递归和模式匹配

例如根据符号变更对链表进行分拆,例如把[1; 4; -3; 2]分为[1; 4]和[-3; 2]。如果不借助低频API以递归模式匹配进行处理,单靠高频函数是很难实现的:

在loop中,进行了三种处理:

  1. 全部元素都是同符号;
  2. 发现有一个符号发生变更;
  3. 在符号变更前已经遍历所有元素。

如果是使用C#中的IEnumerable<T>,或许操作起来略显复杂,但是仍有一些低级API可供使用(使用GetEnumerator进行临时集合和转化)。

  • 从低级转到高级

集合API设计的好处是可以实现从低级到高级的转换。splitAtSignChange函数在根据邻近函数值进行拆分时,可以看成是一个更综合操作的一个实例:

该函数与前个版本十分相似—不同的是增加了额外的参数f来判定什么时候断开链表。虽然函数本身使用了低级API,但提供了转为高级的途径。

再回头看高级的定义是能包含更简单的编程方式。也就是说,根据X轴的临界值来对从1到10的sin值进行链表进行拆分:

可见这就实现了到高级的转换—使用两个简单明了的函数处理拆分问题。

示例#2:3D的领域特定语言

这是另一个典型的例子,特别是在进行自定义对象建模时。

  • 超高级:创建城堡

其实现代码如下:

在高级抽象层面,我们仅仅使用4行代码就把城堡创建好了!但这仅能进行非常受限制的创作(规矩的城墙和塔组成的城堡),或许我们想做得更多。

  • 高级:3D对象组合

如果想使用不同的塔外形该如何处理呢?要查看低级3D渲染代码吗?不必。tower函数本身就是根据另一种语言或抽象等级来进行编写的。一个塔就是一个填色后的圆柱体加上一个填色的有正确朝向的圆锥体:

使用库时,一开始是高级抽象的,但熟悉之后,我们可以进入下一级。在这级中,我们可以打造自己的语言(抽象)例如前述的List.splitAt。

  • 低级:使用OpenGL进行面部渲染

在进行3D渲染时存在一个低级操作。以该库为例,调用OpenGL原始操作是低级的(使用OpenTK包装),这稍微有点复杂:

如果想以更简单的方式来生成图形,我们可以在3D原始操作和渲染之间加多一层,但这不是我们要讨论的。即便如此,我们还是可以看出多级抽象的重要性。最明显的一点是可以从已创建的事物中发现如何实现高级到低级的转换(例如塔是如何组成的),然后以其它方式使用低级原始操作。

换言之,如果你直接以调用OpenGL的方式来生成塔,那么是很难再生成其它形态塔的。但如果有多级抽象机制,这就不是问题了。

综述

本文主要论述了库设计中的多级抽象思想。在你的库中,应该提供高级函数来帮助用户处理80%的任务。对于剩下的15%,应该提供一个低级API。关键的一点是高级API可根据低级API来呈现。这样不但满足了日常需求,还给用户留有二次开发的空间,是更加吸引和友好的。

   
1734 次浏览       29
相关文章

企业架构、TOGAF与ArchiMate概览
架构师之路-如何做好业务建模?
大型网站电商网站架构案例和技术架构的示例
完整的Archimate视点指南(包括示例)
相关文档

数据中台技术架构方法论与实践
适用ArchiMate、EA 和 iSpace进行企业架构建模
Zachman企业架构框架简介
企业架构让SOA落地
相关课程

云平台与微服务架构设计
中台战略、中台建设与数字商业
亿级用户高并发、高可用系统架构
高可用分布式架构设计与实践
最新活动计划
嵌入式软件架构设计 12-11[北京]
LLM大模型与智能体开发实战 12-18[北京]
嵌入式软件测试 12-25[北京]
AI原生应用的微服务架构 1-9[北京]
AI大模型编写高质量代码 1-14[北京]
需求分析与管理 1-22[北京]

专家视角看IT与架构
软件架构设计
面向服务体系架构和业务组件
人人网移动开发架构
架构腐化之谜
谈平台即服务PaaS


面向应用的架构设计实践
单元测试+重构+设计模式
软件架构师—高级实践
软件架构设计方法、案例与实践
嵌入式软件架构设计—高级实践
SOA体系结构实践


锐安科技 软件架构设计方法
成都 嵌入式软件架构设计
上海汽车 嵌入式软件架构设计
北京 软件架构设计
上海 软件架构设计案例与实践
北京 架构设计方法案例与实践
深圳 架构设计方法案例与实践
嵌入式软件架构设计—高级实践
更多...