2.4 代码模块
DO设计过程的第二步是定义系统的代码模块。
乔:既然您已经确定了系统的数据实体,并将它们分组到高级组中,那么是时候考虑一下系统的代码部分了。
你:你说的代码部分是什么意思?
乔:考虑这个问题的一种方式是确定你的系统的功能。
你将再次查看Nancy的需求餐巾纸,这一次您将突出显示代表系统功能的动词短语:
旁白
突出显示需求中与功能相对应的术语
- 两类用户:管理员和会员
- 用户通过电子邮件和密码登录系统。
- 会员可以借书
- 会员和图书管理员可以按书名或作者搜索图书
- 图书馆员可以屏蔽和解锁会员(例如,当他们还书迟到时)
- 图书馆员可以列出会员目前借出的书籍
- 一本书可能有好几本
除此之外,显然会员还可以退还一本书。此外,应该有一种方法来检测用户是否是图书管理员。
您写下系统的功能列表。
旁白
系统的功能
- 搜索一本书。
- 添加图书项目。
- 阻止成员。
- 取消阻止成员。
- 将用户登录到系统。
- 列出会员目前借出的书籍。
- 借书。
- 归还一本书。
- 检查用户是否为图书管理员
乔:太棒了!现在,告诉我哪些功能需要向外界公开?
你:你说暴露在外面是什么意思?
乔:假设图书馆管理系统通过HTTP公开了一个API:API的端点是什么?
你:我明白了。除了检查用户是否是图书馆员之外,它们的所有功能都应该公开。
乔:太好了,现在给每个公开的功能起一个简短的名称,然后把它们集合到一个叫做Library的模块里
所需时间不到一分钟:图2.3显示了包含库公开函数的模块框。
TIP 设计DO系统的代码部分的第一步是将公开的函数聚合到单个模块中。
乔:太漂亮了。您刚刚创建了第一个代码模块。
你:在我看来,它就像一个类:模块和类有什么不同?
乔:模块是功能的集合。在面向对象中,模块由类表示,但在其他编程语言中,它可能是包或命名空间。
你:我明白了。
乔:DO代码模块的重要之处在于它们只包含无状态函数。
你:你是说像Java中的静态方法?
乔:没错!
你:那么这些函数是如何知道它们对哪些信息进行操作的呢?
乔:我们把它作为第一个参数传递给函数。
你:我不明白。你能给我举个例子吗?
乔查看了图2.3中的Library模块的函数列表。
乔:让我们以getBookLendings()为例:在经典的OO中,它的参数是什么?
你:一个图书管理员ID和一个会员ID。
乔:在传统的OO中,getBookLendings是一个接受两个参数的Library类的方法:LibrarianId和MemberId
你:是的。
乔:现在来看微妙的部分:在DO中,getBookLendings是库模块的一部分,除了其他参数外,它还接收LibraryData作为第一个参数。
你:你能告诉我你的意思吗?
乔:当然可以。
乔走近你的键盘,开始打字。
这就是OO中类方法的外观:
class Library {
libraryData // state of the object
getBookLendings(userId, memberId) {
// accesses library data via this.libraryData
}
}
该方法通过this.library访问对象的状态-在我们的例子中是libraryData。对象的状态是对象方法的隐式参数。
TIP 在经典的OO中,对象的状态是对象方法的隐式参数。
在DO中,getBookLendings的签名如下所示:
class Library {
static getBookLendings(libraryData, userId, memberId) {
}
}
Library 的状态存储在Library类外部管理的LibraryData中,LibraryData作为显式参数传递给getBookLendings静态方法。
TIP 在DO中,代码模块的函数是无状态的:它们接收作为显式参数(通常是第一个参数)操作的数据。
同样的规则也适用于 Library 模块的其他函数。它们都是无状态的:它们接收库数据作为第一个参数。
重点 模块是功能的聚合。在DO中,模块函数是无状态的。
您可以应用此规则,并通过包含有关函数参数的详细信息来优化库模块的设计。
乔:太好了。现在,我们已经准备好在高层次上设计我们的系统。
你:什么是DO中的高层次设计?
乔:模块的定义以及它们之间的交互。
你:我明白了。有什么指导原则可以帮助我定义模块吗?
乔:当然可以。系统的高级模块对应于高级数据实体。
你:你是说出现在数据思维导图中的数据实体吗?
乔:没错!
再次查看图2.5中的数据思维导图,您将重点放在高级数据实体上:Library, Catalog 和 User management.
这意味着在系统中,除了图书馆模块之外,我们还有两个高级模块:
- 处理目录数据的Catalog模块
- UserManagement 模块,处理用户管理数据
然后通过添加Catalog和UserManagement模块,画出图书管理系统的总体设计:
- Catalog的函数将CatalogData作为第一个参数接收
- UserManagement的函数接收userManagementData作为第一个参数
图表如下:
您可能还不清楚数据实体是如何在模块之间传递的。目前,您可以将LibraryData看作有两个成员的类:
- 保存目录数据的catalog
- 保存用户管理数据的userManagement
图书馆的功能有一个共同的模式:
- 它们将libraryData作为参数接收
- 它们将LibraryData.Catalog传递给Catalog函数
- 它们将LibraryData.userManagement传递给UserManagement的函数
稍后,在本章中,我们将看到库模块的一些函数的代码。
TIP DO系统的高级模块对应于高级数据实体。