首页 > 代码库 > 8.3.2 构建组合行为

8.3.2 构建组合行为

8.3.2 构建组合行为

 

在清单 8.11 中,检查和报告验证最低收入和最小当前工作年限的函数,明显重复。这些检查有类似的结构:都检查客户的某一属性是否小于最小的允许值。

找出共性是只删除重复第一步,下一步是要看 checkJobYears 和 checkIncome 函数(连同其报表函数)的哪部分是不同的:

■ 检查不同的属性。

■ 使用不同的最小值。

■ 有略微不同的消息。

要写出更简洁的代码,我们可以创建一个函数,把这三个不同的部分作为参数,返回 ClientTest 记录。当我们创建检查列表时,用不同的参数值调用新的函数两次,就创建两个类似的检查。清单 8.13 显示额外的函数(lessThanTest),以及创建检查列表的新方法。

 

清单 8.13 用一个函数创建类似的检查 (F# Interactive)

 

> let lessThanTest readFunc minValuepropertyName = 

     let report client=                                  |

      printfn "Checking ‘%s‘ of ‘%s‘ failed (less than %d)!"     | [1]

                  propertyName client.Name minValue          |

     { Check = (funclient -> readFunc(client) < minValue)     [2]

      Report =report };; 

val lessThanTest : (Client -> int) ->int -> string –> ClientTest  [3]

 

> let tests = 

     [ (lessThanTest(fun client -> client.Income) 30000 "income")   | 创建两个相似的

      (lessThanTest (fun client -> client.YearsInJob)               | 有报表的测试

                            2 "years in the job")                         |

(* more tests... *) ];; 

val tests : ClientTest list

 

像往常一样,类型签名[3]能提供关于这个函数的很多信息。LessThanTest 函数返回值为 ClientTest 类型,它包含了检查和报表函数。检查用三个参数生成的:

1 读客户的数字属性

2 指定必需的最小值(在本例中,表示收入或年数)

3 描述属性(用于报表)

代码首先声明一个嵌套函数report[1],参数为客户,输出检查未通过的原因。这个函数还使用 lessThanTest 函数的参数,因此,当 report 作为结果的一部分返回时,所有的这些参数将捕获在闭包中。当构建将返回的记录值时[2],我们指定 report 作为一个函数值,另一个函数是内嵌的 lambda 函数。

在函数式编程中,使用函数的元组或记录,很常见,它反映了 F# 的开发风格。但在 C# 中,我们使用不同的方法来实现这个示例。现在,我们要看一下开发过程,还要考虑如何用 C# 实现这个示例,并改善当前的F# 版本。

8.3.2 构建组合行为