- 编程与类型系统
- (美)弗拉德·里斯库迪亚
- 935字
- 2025-03-31 19:45:05
1.2.4 可组合性
假设我们想找出一个数值数组中的第一个负数,以及一个字符串数组中的第一个单字符字符串。如果没有思考如何把这个问题分解为可组合的副本,然后拼接成一个可组合的系统,那么可能会创建两个函数:findFirstNegativeNumber()和findFirstOneCharacterString(),如程序清单1.8所示。
程序清单1.8 不可组合的系统

这两个函数分别搜索第一个负数和第一个单字符字符串。如果找不到这样的元素,则函数返回undefined(这是通过不使用return语句退出函数来隐式实现的)。
假设现在有了一个新的需求:当找不到满足条件的元素时,就记录一个错误。那么,我们需要同时更新两个函数,如程序清单1.9所示。
程序清单1.9 更新后的不可组合的系统

这已经不太理想了。如果我们忘记在所有地方应用更新,问题就更严重了。在大型系统中,这些问题会加剧。仔细观察每个函数做的工作,我们会发现它们的算法是相同的,只是在一个函数中,我们根据一种条件操作数值,而在另一个函数中,我们根据不同的条件操作字符串。我们可以提供一个泛型算法,将其操作的类型和检查的条件参数化,如程序清单1.10所示。这种算法不依赖于系统的其他部分,所以我们能够单独处理它。
程序清单1.10 可组合的系统

如果觉得语法看上去有点奇怪,请不必担心。第5章会讲解n => n < 0这样的内联函数,第9章和第10章将讲解泛型。
如果想在这个实现中添加日志记录,只需要更新first的实现。更好的情况是,如果我们找出了一种更加高效的算法,则只要更新实现,就可以让所有调用者受益。
在第10章讨论泛型算法和迭代器的时候将会看到,我们可以使这个函数变得更加通用。目前,它只操作某个类型T的一个数组。可以扩展这个函数,让它遍历任意数据结构。
如果代码不是可组合的,那么我们需要为每种数据类型、每个数据结构和每个条件使用一个不同的函数,即使这些函数在本质上实现了相同的抽象。能够进行抽象,然后混合搭配组件,就减少了大量的重复代码。泛型类型使我们能够表达这类抽象。
将独立的组件组合起来,能够得到模块化系统,并减少需要维护的代码。随着代码规模和组件数量的增加,可组合性会变得很重要。在可组合系统中,不同部分是松散耦合的,同时,每个子系统中的代码不会重复。要处理新的需求,通常可以通过更新单个组件来完成,而不必在整个系统中做大范围修改,同时,理解这些系统要简单一些,因为我们可以单独思考系统的各个部分。