F#探险之旅(六):F#代码的组织

简介:

前言

是的,我们已经学习了如何在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的如何组织程序(

File层次 

现在考虑源码文件内部的基本问题。在使用函数式编程范式时,除了模块,还可以采用F#的自定义类型,F#中的类型分为两类,一是元组(Tuple)或记录(Record)类型,它们类似于C#中的类;二是Union类型,有时又称为Sum类型。通过Reflector可以看到,元组值是Tuple类型的实例,而Tuple实现了 Microsoft.FSharp.Core.IStructuralHash和System.IComparable接口;记录和Union则直接实现了这两个接口。要了解IStructualHash接口的更多内容,请参考Jome Fisher的文章。

而在使用面向对象编程范式时,我们可以像在C#中那样定义.NET类型,比如接口、类、结构、枚举、委托等等。当然这其中的编程细节比较多(建议看看我前面写过的几篇随笔),而且对于同一问题可以采取不同的方案。这需要我们去多多学习和实战,根据不同的需要作出选择。

这里来看另一个具体的问题:如何使用F#中的签名文件(Signature file)。在学习C语言时,接触过函数原型的概念,它给出了函数的名称、参数类型和返回类型,函数签名的含义与函数原型是一样的。如果我们把模块内的函数签名抽取出来,放在单独的一个文件中,这就是签名文件的由来。它的作用在于,它可以控制模块内函数的访问修饰符。如果要使用签名文件,那么它必须与其控制的模块文件成对出现,并且文件名相同。比如:

复制代码
F# Code - myModule.fsi
#light
module FsLib.MyModule

/// 获取一个浮点数的平方值
val square: float -> float

/// 获取一个浮点数的立方值
val cube: float -> float
复制代码

 

复制代码
F# Code - myModule.fs
#light
module FsLib.MyModule

open System

let pow x y = Math.Pow(x, y)

let square x = pow x 2.0
let cube x = pow x 3.0
复制代码


*.fsi即签名文件,这里定义了两个函数的签名:square和cube。*.fs即实现文件,它必须要提供对应的签名文件的所有函数的实现。其它程序集的模块,只能访问*.fsi中具有签名的函数。通过Reflector可以看到,对于myModule.fs中的三个函数,square和cube的修饰符为public,而pow则为internal

由此看来签名文件的作用很像C#中的接口。但事实上,编译后并没有真正生成接口。需要注意的是,如果要为代码添加XML文档注释,需要加在签名文件(如果模块有的话)而不是模块中。下面来看看如何在代码中添加注释。

常规注释 

在F#中,单行注释使用//,而多行注释则使用(* … *)。

XML文档注释 

如果为代码添加了文档注释,可以在编译时生成XML文档,然后借助于一些工具(如SandCastle)就可以生成容易使用的帮助文档。在上面的代码中可以看到,直接使用///可以为模块或其成员添加文档注释,这个要比C#中简便一些。同时也完全可以使用C#中那样完整的文档注释格式(比如使用Summary、Param等节点)。

最后,如果要在F#使用C#类库中的代码,可以参考前面写过的一篇随笔:F#命令式编程,了解关于这方面的内容。

F#的Project可以编译为类库或可执行应用程序(控制台应用程序或Windows应用程序)。我打算在后面的随笔就这两方面展开讨论,并尝试一些有实战意义的小型项目,相信到那时对代码组织的认识会更为准确。

小结 

在初学F#时,我们可以很随便地将代码放在同一模块内做些尝试或者测试。但我们程序员不该是随便的人,随着项目规模的增大,代码的组织问题会变得越发重要,我们应当越加重视。在VS中进行开发时, 整个项目的组织自然地分为了Solution、Project、File三个层次,本文在这三个层次上就代码组织的基本问题做了讨论,写得比较简单,欢迎您来留言讨论 。

(要了解本人所写的其它F#随笔请查看 F#系列随笔索引

参考 
《Foundations of F#》 by Robert Pickering
Detailed Release Notes for the F# Sep 2008 CTP release
园子里Lvxuwen的如何组织程序(
F#先锋维坦F# CTP 1.9.6.0 发行说明(Release Notes)摘要


本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2008/11/05/fsharp-adventure-code-organization.html,如需转载请自行联系原作者。

目录
相关文章
|
Oracle Java 关系型数据库
程序员做开发工作必须要考证么?
众所周知,随着信息技术的迅速发展,程序员已经成为现代社会中不可或缺的一部分。与此同时,关于程序员需要考证的话题也越来越受到关注,以及现在互联网行业内卷严重,催生了程序员继续学习的渠道。随着行业寒冬的影响,互联网行业的程序员竞争越来越激烈,也让程序员再次审视了考证提高自身竞争力的设想。那么本文就来简单探讨一下程序员是否需要考证,以及衡量程序员能力的方式是什么?
221 2
程序员做开发工作必须要考证么?
|
4月前
|
开发者
代码之外:软件开发者的职业素养提升之道
软件开发不仅是编写代码,更涉及职业素养的全面提升。本文探讨了软件开发者如何在沟通技巧、团队合作、持续学习、时间管理和职业规划等方面提升自我。良好的沟通能促进团队协作,持续学习助你紧跟技术潮流,高效时间管理则有助于实现工作与生活的平衡。通过这些方面的努力,开发者能够打造更加成功的职业生涯。
|
4月前
|
程序员 Python
探索编程之旅:从代码到思考的蜕变
【8月更文挑战第33天】在数字世界的迷宫中,编程不仅仅是一种技能,它更是一扇打开思维新境界的大门。本篇文章将带你走进编程的世界,体验从简单代码到复杂逻辑的思考过程,以及这一旅程如何深刻影响我们的思维方式和解决问题的策略。通过具体案例和个人感悟,我们将一起探索编程背后的哲学和生活的启示。
|
2月前
|
存储 算法
探索代码之美:从问题到解决方案的旅程
【10月更文挑战第41天】在编程的世界里,每一行代码都是解决问题的钥匙。本文将带你走进代码的内在世界,通过一个简单的例子展示如何从遇到问题到找到解决方案的过程。我们将一起学习如何分析问题、设计算法、编写代码,并最终实现目标。这不仅是对技术的探索,更是对逻辑思维和创造力的挑战。让我们一起踏上这段充满智慧与乐趣的旅程吧!
31 1
|
3月前
|
存储 供应链 数据库
探索代码之美——从问题到解决方案的旅程
【10月更文挑战第15天】在编程的世界里,每一行代码都是构建数字宇宙的基石。本文将通过一个简单的例子,展示如何从遇到问题到找到并实现解决方案的过程。我们将一起经历思考、规划、编码和测试的全过程,体验技术解决问题的魅力。
42 3
|
3月前
|
测试技术 持续交付 开发者
编程之道:开发者的自我提升之旅
在软件开发的世界里,每位开发者都是用代码绘出数字化画卷的艺术家。本文从技术深度与广度的平衡、代码的简洁之美、持续集成与部署、代码审查、测试驱动开发、有效沟通、时间管理和面对失败的勇气等八个方面,分享了职业心得,帮助开发者在技术和心灵上共同提升,勇敢面对每一次挑战,在编程之路上不断前行。
|
3月前
|
前端开发 API 开发者
🥇前端宝藏:多项目掌握技能的冒险之旅🏆
在前端开发的学习旅程中,实践是提升技能的关键。本文介绍了多个前端项目,包括计算器、天气应用、经典游戏等,涵盖了从React到Svelte的各种技术栈。每个项目都附有在线演示和源代码,旨在帮助读者深入理解实现细节,激励更多人参与实际项目开发。通过这些项目,读者可以将理论知识转化为实践,拓展职业机会。
25 0
|
6月前
|
JavaScript 前端开发 Java
代码之舞:从编程新手到资深开发者的旅程
【7月更文挑战第19天】编程,一种现代魔法,让无数人为之着迷。本文将通过个人的技术感悟,探讨如何从一个对代码一无所知的新手成长为一名能够自如驾驭复杂项目的资深开发者。我们将穿越编程语言的选择、学习资源的利用、项目实践的重要性以及持续学习的必要,最终达到技术与创造力的和谐共舞。
71 10
|
7月前
|
前端开发 开发者
编织代码的诗篇:我的技术感悟之旅
【6月更文挑战第10天】在数字世界的织布机上,每一行代码都如同细腻的丝线,交织成我技术生涯的华美篇章。本文将带你穿梭于我与代码共舞的日子,感受那些静默中涌现的灵感,以及在挑战与创造间不断进化的思维。
40 3
|
8月前
|
算法 Java 程序员
程序员职业发展之旅:从代码入门到身体管理的完美进化
程序员职业发展之旅:从代码入门到身体管理的完美进化

热门文章

最新文章

下一篇
开通oss服务