阅读更多

1顶
0踩

企业架构
编者按:本文作者Tomas是F#语言的专家以及导师、计算机科学家,曾出版过有关F#的教程。本文重点介绍了如何设计组合化的库以及如何避免在库设计时进行回调。Tomas倡导以库而不是框架的方式进行开发。以下为译文。

框架VS.库

框架和库有什么区别呢?两者的主要不同之处在于如何使用它们以及编写什么样的代码。

框架——框架控制了系统的运行,并定义了扩展点 (接口)来让用户进行实施;
库——库把系统运行控制权交给用户,并定义了功能和类型供用户使用。
框架和库之间的区别可用上图表示。框架定义了一个结构,你不得不将其填充好;而库则需要你围绕其提供的结构进行编码。

为什么不建议使用框架?

框架是不可组合的
框架最大最显著的弱点是不可组合。如果你正在使用两个框架,这两者之间往往是很难兼容的;谁包含谁,谁是谁的外延也是不清晰的。

如果是库,情况则有所不同。因为你才是决策人,所以能够同时调用不同的库,虽然这会增加一定的编程复杂度,但至少是能够实现的。



难以对框架进行探索
框架另一个大问题是很难进行测试和探索。在F#中,载入一个库并透过不同输入来检查输出和库的运行是很有用的。例如,可以使用Web开发库 Suave来启动一个简单的Web服务器,代码如下:



代码片中首先载入了库,然后以默认方式调用startWebServer。该方式是非常有用的,因为可以让用户尝试不同的参数来对输出结果进行对比。

框架定型了用户代码
框架还有个问题是控制了用户代码的结构。一个典型的例子是如果你正在使用一个框架,它会要求你继承一些抽象基类然后运行具体的方法。例如XNA框架中的Game类(虽然XNA框架终止了,但是其模式在另一个框架继续使用着):
class Game {
  abstract void Initialize();
  abstract void Draw(DrawingContext ctx);
  abstract void Update();
}

在Initialize()中,需要对游戏用到的资源进行预载;Update()在进行状态刷新时会被反复调用;Draw()则在更新屏幕时用到。这难道不正是命令式编程吗?所以我们很可能会写出类似的如下代码:



代码作用是让人物往右移动。基于框架结构进行编程是有难度的,而这里我使用了最直接的方法来实现。变量x表示的是人物位置,而mario则用于存放人物图像资源。

虽然这在C#中或许会更加简洁,但前提是要忽略全部的检查。使用option目的是让代码更加安全(避免mario没有定义就在Draw()中使用)。此外,谁能保证Initialize()一定在Draw()执行前就调用完毕?

如何避免框架错误

接下来我会讲述如何使用库而不是框架的具体原因。

支援交互性的探索
即使你没有使用F#来编写库,但是F#的交互性仍非常值得一试。F#不但可以用来编写库,其强大的交互性更使得库的运用变得十分简便。(如果是.NET平台,可以尝试 LINQPad)。

请看下面这个例子,它展示了如何使用F#格式库来把包含在文件夹中的F#脚本转为HTML或对某单一文件进行操作。

如果是第一次接触,我会首先看有关库的说明,然后打开命名空间找到Literate,然后进行尝试,例如输入“.”。

我认为良好的库都支持类似的探索步骤。再看另外一个例子, FunScript ;用于把F#代码转为JavaScript。以下生成的JavaScript代码作用是为异步循环进行计数,在<tiltle>页面按秒执行:



类似地,我们都可以遵循上一个例子的学习途径掌握到相关用法。

尽量进行简单的回调
接下来再看两个例子。第一个是以标准链表的方式对数据进行处理;另一个是使用上述链表方式读取输入,然后检查数据,最后再进行处理。



这两个例子有什么不同之处呢?对于链表List函数,常常是一个单一函数作为一个参数使用。而这个函数是无状态的。

在第二个例子中,指定了两个函数。于我而言,这通常预示着有复杂的事情发生。其次,readAndProcess要求我们返回例子1中的字符串状态,然后把字符串作为下一函数的输入。这会引起一个潜在的问题。如果例子2需要例子1转入其它状态,该如何处理呢?

让我们进入readAndProcess来看它执行了什么操作;首先是进行异常处理,然后对输入进行检查。



如果对其进行改进,要如何做呢?我们不妨把它分解为两个函数:



现在,validateInput变得简化了,如果输入是有效的则返回Some()的处理结果。而ignoreIOErrors函数仍作为参数使用。结合新函数,可以写成:



代码还是三行,但是更加清晰了,虽然比之前长了些。这样一来程序变得到简化,方便弄清楚其来龙去脉。

总的来说把函数作为参数使用是可以的,但是要注意尽量做到简化。特别是牵涉到状态的多次变化时,换另外一种处理方式或许会更好。

使用事件和异步进行反向回调
前面我们结合一个简单的游戏引擎讲述了框架是如何影响我们编程的,如果在不使用可变域和执行指定类的情况下,又该如何处理呢?在F#中,可以尝试异步工作流和基于事件的编程模型来代替。

其思路是使用触发事件而不是编写虚方法。因此,Game的定义变为:



结合F#异步处理以及库的主动控制特长,我们可把代码改写为:



代码中首先对资源和Game对象进行了初始化;然后做了循环处理,使用AwaitObservable对Update或Draw事件进行监听。虽然我们无法对游戏状态和屏幕更新进行控制,但是在初始化时我们是可以做到的,检查游戏何时运行以及等待事件的发生。

asnc{..}的使用是关键所在。我们可以使用AwaitObservable来实现在更新或重绘需要时恢复计算。这样做的好处是可以实现更加复杂的操作,具体可参考这个例子Phil Trelford's Fractal Zoom。另外F#的agents代理可以实现类似的逻辑控制。

如果对F#不熟悉,或许会对上述代码困惑。但我的目的是说明控制权掌握在自己手中的重要性,这样可以写出自己的抽象逻辑,这也是接下来要说的。

使用多重抽象逻辑
请再看看前述的Game例子,虽然低阶抽象给予了充分的控制权,但是很多时候,我们希望写出的游戏是同时具备重绘和更新功能的。

这实现起来也不难,只需把某些部分作为参数使用:



startGame抽象实现了在初始化时把两个函数作为参数使用。Update函数进行状态刷新,draw函数使用DrawingContext重绘状态。这样一来,我们的例子可变为4行代码:



因此只要仔细阅读startGame的代码,按需对其进行改动,便可实现全权控制。对比于建基于一个脆弱库之上的程序,这种方式难道不更稳定可靠吗?

设计可组合的库
对于库来说,可组合属性是我们选择它而不是框架的原因之一。例如FsLab,这是一个用于F#的数据科学库(包括Deedle,Math.Net Numerics等),以单个脚本的方式链接呢其他的库(源代码)。

两个简单的例子是矩阵和框架的互转Matrix.toFrame,Frame.toMatrix。



该转换操作起来是很简单的,因为Deedle框架和Math.Net矩阵都能转化为一个2维数组,所以通过数组可方便地实现两者的互转。因此,即使是很复杂的库,我们都应该为用户保留足够的库合成权以实现更强大的功能(或者改写)。

写在最后

本文着重从可组合和避免回调方面对库和框架进行比较。进一步说,框架模式不仅存在于软件,在日常生活也是经常遇到的。例如参团游,从一开始,交通、住宿、游玩行程等都已经被固定了;而自由行则类似于库的组合,任何细节都需要亲力亲为,从而实现全权控制。虽然参团游很方便,但是对于我,特别是软件开发,我还是更倾向于我的地盘我做主!
来自:Tomas Petricek's blog
  • 大小: 10.1 KB
  • 大小: 11.2 KB
  • 大小: 23.4 KB
  • 大小: 19.2 KB
  • 大小: 18.5 KB
  • 大小: 17.3 KB
  • 大小: 17.4 KB
  • 大小: 11.7 KB
  • 大小: 10.5 KB
  • 大小: 8.9 KB
  • 大小: 7.2 KB
  • 大小: 32.7 KB
  • 大小: 19.1 KB
  • 大小: 7.3 KB
  • 大小: 11.4 KB
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 如何利用多级抽象思维来设计库?

    编者按:之前,我们曾发表《函数式语言库模式:框架是魔鬼?》该文论述了库与框架之间的区别,及如何设计组合化的库。而本文作者在此之前,还发表了一篇《Librarypatterns:Multiplelevelsofabstraction》,结合具体...

  • 从函数式编程到声明式UI

    1.声明式UI的现状 ...之后不断涌现出的JQuery等各种组件库,也只是围绕Dom的操作进行了一些封装,并没用改变这种命令式操作Dom的模式。 直到React的出现,创造性地提成了声明式UI的概念才彻底颠覆了命令式的开发...

  • 如何高效、优雅、愉快地阅读项目源码?

    代码是形式,逻辑是神韵。引子本文探索如何阅读成熟框架的源码。温馨提示欲速则不达。阅读源码很容易理解为就是直接去阅读代码本身。实际上,代码只是形式,逻辑才是神韵。凡是有助于去理解逻辑,理解其...

  • 优雅的阅读框架源码

    编程模型:特别的编程手法和技巧,比如读 hystrix 源码,就要先熟悉函数式编程和响应式编程。 如何找到论述原理机制的相关文献呢?有一些基本方法可循: 经典书籍:比如数据结构与算法,就有《算法导论》、《算法》...

  • 设计模式之禅学习总结

    设计模式之禅学习总结单一职责原则 SRP里式替换原则 LSP依赖倒置原则 DIP接口隔离原则迪米特法则LoD开闭原则:单例模式单例模式的通用类图如下图单例模式的优点单例模式的缺点单例模式的使用场景工厂模式工厂方法...

  • 设计模式之美 精华总结 笔记(二)

    文章目录设计模式之美 精华 笔记(二)一、面向对象精解1、封装2、抽象3、继承4、多态5、思考:为什么有些语言不允许多继承二、面向对象优于面向过程的地方1、形式上2、复用、扩展、维护角度上3、思考角度4、总结5、...

  • 混合编程黑科技:跨语言编程问题迎刃而解的3个要点

    首先,混合编程是什么鬼?这个世界上编程语言真不少,光常用就有:C、C++、Java、C#、Objective-C、Javascript、Python、Lua、Swift等等等,遑论一些专...

  • 那些一口气那些数十个大厂offer的都是什么魔鬼操作

    Q :Java 如何调用 c 、c++ 语言? Q :jni 如何调用 java 层代码? Q :进程间通信的方式? Q :Binder 机制 Q :简述 IPC ? Q :什么是 AIDL ? Q :AIDL 解决了什么问题? Q :AIDL 如何使用? Q :...

  • Web前端面试指导(五十一):javascript的编写规范有哪些?

    全局命名空间污染与 IIFE 总是将代码包裹成一个 IIFE(Immediately-Invoked Function Expression),用以创建独立隔绝的定义域。... 第三方库,window 引用,被覆盖的未定义的关键字等等)。 不推荐 var x = 10,

  • 设计模式(Design Pattern,DP)

    文章目录设计模式的产生背景1、 设计模式的六大设计原则1.1 开闭原则:Open Closed Principle,OCP1.1.1 开闭原则的定义1.1.2 开闭原则的作用1.2 单一职责原则:Single responsibility principle,SRP1.2 .2 单一...

  • 这一年,这些书:2022年读书笔记

    花了那么多钱那么多时间上了那么多年的学,竟然没有主动自学过任何在社会上实际有用实际有效的技能——比如检索式阅读,比如创造性写作,比如演讲,比如策划,比如领导,更不用说投资了! 在一些事儿上,技巧起着百...

  • 友好的开发框架-Asta4D(1):为什么Asta4D

    公司去年开源了一个WEB框架-Asta4D,这个框架用来支撑公司的服务网站,经过一年的开发,已经基本达到成熟的阶段了。问题是,在WEB框架汗牛充栋的今天,我们为什么还要开发一个新的框架呢? 我们本来是用Scala开发的...

  • atitit.提升研发效率的利器---重型框架与类库的区别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的区别与设计原则   1. 框架的意义---设计的复用 1 1.1. 重型框架就是it界的重武器。...2.4. 框架模式就是参团游,而自由行则类似于库的组合 3 3. 框架的特点 3

  • atitit.提升研发效率的利器---重型框架与类库的差别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的差别与设计原则 1.框架的意义---设计的复用 1 1.1.重型框架就是it界的重武器。...2.4.框架模式就是參团游,而自由行则类似于库的组合 3 3.框架的特点...

  • FastReport 模版打印如何实现

    FastReport 模版打印如何实现

  • 使用运算放大器模拟反相放大器的闭环电压增益simulink.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

  • 基于java的抗疫医疗用品销售平台设计与实现.docx

    基于java的抗疫医疗用品销售平台设计与实现.docx

  • vue+SpringBoot749乡村日常政务管理系统的设计与实现java毕业设计源码含论文.rar

    jdk版本:jdk1.8+ 前端:vue.js+ElementUI 开发工具:IDEA 或者eclipse都支持 编程语言: java 框架支持:springboot 数据库: mysql 版本不限 数据库工具:Navicat/SQLyog都可以 详细技术:java+springboot+vue+MYSQL+MAVEN 前端采用的Vue框架,后端采用java语言,sprinboot框架,mybatis操作数据源,使用软件:idea,eclipse、MySQL。完成了用户登录管理等模块的设计与实现。完成了系统数据库的设计,并基于MySQL数据库管理系统

Global site tag (gtag.js) - Google Analytics