首页 > 代码库 > 9.4 具体的对象类型

9.4 具体的对象类型

9.4 具体的对象类型

 

面向对象编程中的最重要的结构,就是类的声明。它的价值体现用 F# 写的库,可以在 C# 中使用,因为从 C# 中引用F# 声明的类时,看起来就像普通的类。从概念上讲,类有一点像带成员的记录,因为,它们把值存储在字段中,并提供成员进行访问;类还有另外的功能,在 F# 中,出现下列情况,通常使用类:

■ 需要封装数据和行为时。

■ 在迭代开发过程的后期,把简单的元组或记录转换成更进化的类型,以隐藏内部实现。

■当类型需要在构造器的内部运行一些计算时。

当需要设计可扩展的类型,支持添加操作时,不要使用类;实现继承和虚拟方法很少使用。

我们先看一个可能是最简单的例子。清单 9.14 显示了一个有构造函数的类声明,它有几个属性和一个方法。

 

清单 9.14 带有客户信息的类 (F# Interactive) 

> type ClientInfo(name, income, years)=      [1]

     letloanCoefficient = income / 5000 * years  | 在构造时运行

     do printfn"Creating client ‘%s‘" name      |

 

     member x.Name =name     |

     member x.Income =income  | [2]

     member x.Years =years      |

 

     member x.Report()=                                   | [3]

      printfn "Client: %s, loan coefficient: %d" name loanCoefficient |

;; 

type ClientInfo = (...)

 

> let john = new ClientInfo("JohnDoe", 40000, 2);;   <-- 创建类,运行构造函数

val john : ClientInfo 

Creating client ‘John Doe‘

 

> john.Report();;     <-- 调用类的方法

Client: John Doe, q=16 

val it : unit = ()

 

类声明的开始是类的名字和构造函数参数[1]。接下来的几行,直到第一个成员声明之前,都会在构造期间执行;这部分代码构成了隐式构造函数(implicit constructor)。构造函数的参数(如 name 等)和在初始化代码中声明的值(如 loanCoefficient),在类的内部任何地方都可以访问;这是非常有用的,因为,C# 的构造函数通常只复制其参数值给私有字段,因此,它们能够从其他地方访问。如果只在构造函数代码内部使用参数,就不保存为字段,因为,编译器知道不再需要它。

接下来,是类声明的三个成员,把构造函数的参数值公开为客户的属性[2],和一个方法[3]。就像在F# 的数据类型上添加成员一样,前缀 x. 表示类的当前实例,可以使用值 x 来访问;我们可能会用它来调用其他方法,或者读其他属性。

 

注意

 

F# 提供声明类的功能,要比我们在这个例子中看到丰富得多。F# 语言的目标是成为.NET 的一等公民(first-class .NET citizen),所以,在 C# 几乎所有能用的,都可以转换到 F#;然而,在通常的 F# 编程中,我们并不需要高级的 .NET 对象模型的功能,比如,重载构造函数(overloaded constructors)、重载方法(overloadedmethods),还有,公开访问字段。

本书的目的是介绍函数式概念,而不是解释每一项 F# 功能,因此,我们只讨论 F# 提供的最有用的面向对象的构造,看它们如何使用函数风格。要找到更多关于类声明的信息,可以浏览本书的网站,另外,还可以参考本书结尾的参考资料一节中提到的 [F# 文档] 和 [F# 语言规范] 。

 

前面示例中的类仍然是纯函数式的,因此,它没有任何可变状态;这说明了面向对象和函数范式是可以很好地结合在一起的。

 

9.4 具体的对象类型