前言
是的,我们已经学习了如何在F#中使用各种范式(函数式、命令式、面向对象)进行编程。但是目前还仅限于在单个模块内编写,要知道,不管是采用哪种语言或者范式编程,如果项目规模大了,都不适合把所有代码放在单个模块内。
在常规的.NET项目中(比如C#+ASP.NET),我们往往会选择使用Solution的概念作为整个(独立)问题域的解决方案,Solution以下则是Project、File。这些概念在物理上往往表现为程序集(类库或可执行程序)、类文件等,如果项目和文件数量较多,就该好好考虑如何在组织它们。下面从这三个层次上分别来讨论一下。
Solution层次
这里主要考虑的是Project之间的相互关系,此时基本上我们可以忽略语言的不同,也可以说在这个层次上,语言的影响不大。所以说我们把那些在用C#开发时采用的代码组织原则搬过来用。比如Martin Fowler在《企业应用架构模式》中谈到的内容,比如Robert Martin在《敏捷软件开发》中提到的关于包的设计原则,还包括.NET社区中关于PetShop架构的讨论等等,都可以加以借鉴。关于这方面的内容已有大量相关的讨论,在此不再赘述。
这里只谈一个具体的问题:如何添加对其它程序集的引用。在F# CTP 1.9.6.0之前,添加对程序集的引用需要#I和#r指令,#I用来指定要引用的程序集的目录,#r则用来指定要引用程序集的路径(包含文件名,可以是相对路径或绝对路径)。这两个指令既可以放在代码文件中,也可以放在编译选项中。其中有个小窍门,注册表中.NETFramework节点下包含了各.NET版本的一些信息,其中的AssemblyFoldersEx中有若干个目录信息,如果程序集所在目录出现在AssemblyFoldersEx中,就可以直接使用#r和文件名来添加引用了。
在CTP版本中,可以像常规的C#/VB.NET项目中那样,为项目添加对其它程序集的引用(包括引用同一解决方案中的其它项目):
而#r只能用于fsx脚本文件或者放在编译选项中。
Project层次
现在假定你已经对上述设计原则有了足够的了解,并运用这些原则完成了设计,下一步就是如何使用F#来实现这些设计。现在我们进入到了Project这个层次,需要考虑Project中各代码实体之间的关系,这些实体可以是物理上的源码文件,也可以是逻辑上的模块、类型、配置等。F#中最基本的组织结构是命名空间和模块,命名空间的概念与C#中的一样。借助于Reflector可以看到模块在编译之后就是静态类,我们在为模块添加成员时要了解,这是在向一个静态类添加成员。关于命名空间和模块的相关知识,强烈推荐Lvxuwen的如何组织程序(上、下)。