5.3.3添加类型还是函数

来源:互联网 发布:2016最新挂机赚钱软件 编辑:程序博客网 时间:2024/05/19 07:07

5.3.3 添加类型还是函数

 

    正如我们早先提到过的,在 F# 和 C# 中,函数 Schedule 数据类型在一个方向不可扩展:很难添加一个新的事件的类型。在 F# 中,出现困难的原因是,需要修改类型声明;如果它在一个共享库中,必须重新编译这个共享库。同样,在 C# 版本中,我们有一个 Tag 属性,这使得添加新类型更困难。另一方面,这种设计的好处是,使我们能够很容易为了处理计划,而添加新的功能。

    让我们研究一下函数和面向对象解决方案之间的差异。图 5.2 显示两个类层次结构表示两种可能的方法。在面向对象的版本中,所有的功能都被括在虚拟方法。函数版本公开的 Tag 属性可用于标识值表示的那个选项。

image

图 5.2 表示计划,使用通常的面向对象设计(左图),使用带 Tag 属性的函数方法(右图)


    下面列出了函数编程风格(FP)与通常的面向对象风格的之间的主要区别,我们看到在代码示例中所看到的。

    ■ FP 版本使添加处理数据类型的新功能容易,通过编写使用模式匹配的一个函数就能实现。但是,添加新类型的表示困难。

    ■ 面向对象的版本使添加新类型的表示很容易,通过编写新的继承类并实施其虚拟的方法实现。但是,添加新的虚拟方法困难。

    ■ 在 FP 版本中,单一功能的代码都在一个地方,所以,与一种计算有关的所有代码是在单独的函数中。

    ■ 在面向对象版本中,单个类型的代码都 在一个地方,这意味着,使用特定表示的所有代码都在一个类声明中。

    如你所见,关键问题是我们是要使哪一个更容易,是添加新类型,还是新函数。经验表明,在函数编程中,更常见的是,要向现有类型添加新的功能。

    如果你熟悉通常的设计模式,可能还记得访问者模式,这是面向对象的处理数据结构的方式,就像差别联合。我们将第 7 章讨论递归的差别联合时再说,因为,它通常用于处理复杂的程序数据,而不是简单的值。也要等到第 7 章,才会讨论是否选择差别联合,因为这个问题更多的与程序数据有关,但是,你可以先看看侧边栏“在现实世界中的差别联合”,有几个使用差别联合的例子。

 

在现实世界中的差别联合

 

    使用差别联合更优雅实现类层次结构的一个例子是,可以的.NET 3.5 的 LINQ 项目引入的表达式(Expression)类型,它用来存储表达式树,这是表示数据结构,解析表达式的源代码(例如,1 + x)。这个类型具有继承类,对于每个可能的表达式类型,如 BinaryExpression,可以表示加和(或)其他二元运算,例如,ConstantExpression,这用于存储文字。这个类型也有一个属性类似于 Tag 属性,但它使用的名字是 NodeType。一般而言,每当你处理某种形式的源代码,或由用户输入的简单表达式,差别联合可能是正确的选择。

    差别联合很有用的另一个例子是,表示如二叉树的数据结构。树可以携带一些值的叶子,或者是内部的树节点,由两个二叉树组成。树是函数编程中经常使用的数据结构,所以,会在第 8、 10、 15 章中看到。

 

    在本章中,我们讨论了简单值:任何简单的表示为有限的可选值集合的通用值,应该始终选择差别联合。这是因为,对于这种值,几乎可以肯定的是想要添加新的功能,而不是添加新的类型。有一个差别联合,在函数编程中非常有用的,存在于所有的函数语言:F# 中它被称为选项(option)类型。