Perl 模块层次结构和组合
Perl modules hierarchy and composition
关于 Perl 的阅读越来越多,我开始怀疑我在当前项目中如何组织我的模块。
我有一个主命名空间 - 我们称它为 "MyProject"。
在这个项目中,基础数据是图表,其中每个对象都有一个 class。对象与关系相关联。对象和关系都可以有属性。
项目的一部分我使用模型来验证这些图表。
所以我有一个模型 class,它由 class Class、关系和属性的对象组成。
Classes Class,关系和属性仅供 class 模型使用,因此按如下方式组织模块对我来说很有意义:
- 我的项目::模型
- 我的项目::模型::Class
- 我的项目::模型::关系
- 我的项目::模型::属性
但我开始认为,只有当我敢于在 CPAN 中发布我项目的部分内容时,这对我才有意义。我想人们会相信 Class,Relation 和 Attribute 是继承 Model 而不是组合它。
所以:我应该这样重新组织我的模块吗:
- 我的项目::模型
- 我的项目::Class
- 我的项目::关系
- 我的项目::属性
或者可以通过附加名称表明 Class、关系和属性是模型的一部分?
- 我的项目::模型
- 我的项目::模型Class
- 我的项目::模型关系
- 我的项目::模型属性
我的问题:在组合方面,目前认为模块组织和命名的最佳实践是什么?
您的担心是正确的。通常,包由 inclusion 或 inheritance 命名。我要编一个更现实的例子。假设我们正在建立一个在线商店。
包容
您首先为您的项目选择一个命名空间。在商业世界中,您经常会看到以公司名称开头的名称空间,以区分专有模块和 CPAN 模块。所以项目的命名空间可以是:
OurCompany::Shop
那么应用程序的主要 class 或模块可能调用相同,所以我们有一个
OurCompany/Shop.pm
我们将拥有制作网上商店所需的一堆东西。如果我们的项目是 MCV,就会有控制器和模型之类的东西。所以我们可能有这些东西:
OurCompany::Shop::Controller::ProductSearch
OurCompany::Shop::Controller::Cart
OurCompany::Shop::Controller::Checkout
OurCompany::Shop::Model::Database
所有这些都直接映射到模块。
OurCompany/Shop/Controller/ProductSearch.pm
OurCompany/Shop/Controller/Cart.pm
OurCompany/Shop/Controller/Checkout.pm
OurCompany/Shop/Model/Database.pm
但是没有OurCompany::Controller
作为基数class。该名称只是一个名称空间,用于对事物进行排序。
还有一些东西就在那里,并被 OurCompany::Shop 使用,比如 Session 引擎。
OurCompany::Shop::Session
那些在项目之后进入第一级,除非它们非常具体。
现在会话系统背后当然有某种引擎。假设我们很喜欢并在我们的会话中使用 Redis。如果我们自己实现通信(我们不会这样做,因为 CPAN 已经做到了),我们会将该实现粘贴到
OurCompany::Shop::Session::Engine::Redis
唯一使用此模块的是 OurCompany::Shop::Session。主应用程序甚至不知道使用什么引擎。也许你的开发机器上没有 Redis,所以你使用的是普通文件。
OurCompany::Shop::Session::Engine::File
它们都在那里,它们属于::Session,但它们不会被系统的任何其他部分使用,所以我们将它们归档到它们所属的地方。
继承
我们还将有产品1。基础产品 class 可能是这个。
OurCompany::Shop::Product
并且有一个文件。
OurCompany/Shop/Product.pm
只是这个基础产品永远不会被商店直接使用,除了检查某些东西必须在它们的继承树中有 ::Product(这是一个 isa
检查)。所以这和::Session是不一样的,直接获取。
但是我们当然卖不同的东西,它们有不同的属性。它们都有价格,但鞋子有尺寸,硬盘有容量。所以我们创建 subclasses.
OurCompany::Shop::Product::Shoe
OurCompany::Shop::Product::HardDrive
那些都有自己的文件。
OurCompany/Shop/Product/Shoe.pm
OurCompany/Shop/Product/HardDrive.pm
我们可能还会区分机械硬盘和 SSD,因此我们制作了一个 ::SSD subclass。
OurCompany::Shop::Product::HardDrive::SSD
OurCompany/Shop/Product/HardDrive/SSD.pm
所以基本上,如果事物属于彼此,它们就会放在同一个命名空间中。这是我们的库的树视图。
.
└── OurCompany
├── Shop
│ ├── Controller
│ │ ├── Cart.pm
│ │ ├── Checkout.pm
│ │ └── ProductSearch.pm
│ ├── Model
│ │ └── Database.pm
│ ├── Product
│ │ ├── HardDrive
│ │ │ └── SSD.pm
│ │ ├── HardDrive.pm
│ │ └── Shoe.pm
| ├── Product.pm
│ └── Session.pm
│ │ └── Engine.pm
│ │ ├── File.pm
│ │ └── Redis.pm
└── Shop.pm
总结一下:
- 对于您的主模块,文件名是项目包名称的最后一部分。其他一切都在那里。
- 属于一起的东西被分组在一个名称空间下。
- 从某个东西继承的东西在那个东西的命名空间下。
- 只被一个特定的东西使用的东西放在那个东西下面。
切勿将 MyProject::AB 之类的东西附加在一起,以表明它属于 MyProject::A。始终使用名称空间分隔符来组织您的名称空间。考虑一下,这看起来完全错误:
OurCompany::ShopProductShoe
1) 可能我们还有一个后台应用程序也使用相同的产品 classes。在那种情况下,我们可能将它们设为 OurCompany::Product,并且它们被两个不同的项目使用,OurCompany::Shop 和 OurCompany::BackOffice。
关于 Perl 的阅读越来越多,我开始怀疑我在当前项目中如何组织我的模块。
我有一个主命名空间 - 我们称它为 "MyProject"。
在这个项目中,基础数据是图表,其中每个对象都有一个 class。对象与关系相关联。对象和关系都可以有属性。
项目的一部分我使用模型来验证这些图表。 所以我有一个模型 class,它由 class Class、关系和属性的对象组成。
Classes Class,关系和属性仅供 class 模型使用,因此按如下方式组织模块对我来说很有意义:
- 我的项目::模型
- 我的项目::模型::Class
- 我的项目::模型::关系
- 我的项目::模型::属性
但我开始认为,只有当我敢于在 CPAN 中发布我项目的部分内容时,这对我才有意义。我想人们会相信 Class,Relation 和 Attribute 是继承 Model 而不是组合它。
所以:我应该这样重新组织我的模块吗:
- 我的项目::模型
- 我的项目::Class
- 我的项目::关系
- 我的项目::属性
或者可以通过附加名称表明 Class、关系和属性是模型的一部分?
- 我的项目::模型
- 我的项目::模型Class
- 我的项目::模型关系
- 我的项目::模型属性
我的问题:在组合方面,目前认为模块组织和命名的最佳实践是什么?
您的担心是正确的。通常,包由 inclusion 或 inheritance 命名。我要编一个更现实的例子。假设我们正在建立一个在线商店。
包容
您首先为您的项目选择一个命名空间。在商业世界中,您经常会看到以公司名称开头的名称空间,以区分专有模块和 CPAN 模块。所以项目的命名空间可以是:
OurCompany::Shop
那么应用程序的主要 class 或模块可能调用相同,所以我们有一个
OurCompany/Shop.pm
我们将拥有制作网上商店所需的一堆东西。如果我们的项目是 MCV,就会有控制器和模型之类的东西。所以我们可能有这些东西:
OurCompany::Shop::Controller::ProductSearch
OurCompany::Shop::Controller::Cart
OurCompany::Shop::Controller::Checkout
OurCompany::Shop::Model::Database
所有这些都直接映射到模块。
OurCompany/Shop/Controller/ProductSearch.pm
OurCompany/Shop/Controller/Cart.pm
OurCompany/Shop/Controller/Checkout.pm
OurCompany/Shop/Model/Database.pm
但是没有OurCompany::Controller
作为基数class。该名称只是一个名称空间,用于对事物进行排序。
还有一些东西就在那里,并被 OurCompany::Shop 使用,比如 Session 引擎。
OurCompany::Shop::Session
那些在项目之后进入第一级,除非它们非常具体。
现在会话系统背后当然有某种引擎。假设我们很喜欢并在我们的会话中使用 Redis。如果我们自己实现通信(我们不会这样做,因为 CPAN 已经做到了),我们会将该实现粘贴到
OurCompany::Shop::Session::Engine::Redis
唯一使用此模块的是 OurCompany::Shop::Session。主应用程序甚至不知道使用什么引擎。也许你的开发机器上没有 Redis,所以你使用的是普通文件。
OurCompany::Shop::Session::Engine::File
它们都在那里,它们属于::Session,但它们不会被系统的任何其他部分使用,所以我们将它们归档到它们所属的地方。
继承
我们还将有产品1。基础产品 class 可能是这个。
OurCompany::Shop::Product
并且有一个文件。
OurCompany/Shop/Product.pm
只是这个基础产品永远不会被商店直接使用,除了检查某些东西必须在它们的继承树中有 ::Product(这是一个 isa
检查)。所以这和::Session是不一样的,直接获取。
但是我们当然卖不同的东西,它们有不同的属性。它们都有价格,但鞋子有尺寸,硬盘有容量。所以我们创建 subclasses.
OurCompany::Shop::Product::Shoe
OurCompany::Shop::Product::HardDrive
那些都有自己的文件。
OurCompany/Shop/Product/Shoe.pm
OurCompany/Shop/Product/HardDrive.pm
我们可能还会区分机械硬盘和 SSD,因此我们制作了一个 ::SSD subclass。
OurCompany::Shop::Product::HardDrive::SSD
OurCompany/Shop/Product/HardDrive/SSD.pm
所以基本上,如果事物属于彼此,它们就会放在同一个命名空间中。这是我们的库的树视图。
.
└── OurCompany
├── Shop
│ ├── Controller
│ │ ├── Cart.pm
│ │ ├── Checkout.pm
│ │ └── ProductSearch.pm
│ ├── Model
│ │ └── Database.pm
│ ├── Product
│ │ ├── HardDrive
│ │ │ └── SSD.pm
│ │ ├── HardDrive.pm
│ │ └── Shoe.pm
| ├── Product.pm
│ └── Session.pm
│ │ └── Engine.pm
│ │ ├── File.pm
│ │ └── Redis.pm
└── Shop.pm
总结一下:
- 对于您的主模块,文件名是项目包名称的最后一部分。其他一切都在那里。
- 属于一起的东西被分组在一个名称空间下。
- 从某个东西继承的东西在那个东西的命名空间下。
- 只被一个特定的东西使用的东西放在那个东西下面。
切勿将 MyProject::AB 之类的东西附加在一起,以表明它属于 MyProject::A。始终使用名称空间分隔符来组织您的名称空间。考虑一下,这看起来完全错误:
OurCompany::ShopProductShoe
1) 可能我们还有一个后台应用程序也使用相同的产品 classes。在那种情况下,我们可能将它们设为 OurCompany::Product,并且它们被两个不同的项目使用,OurCompany::Shop 和 OurCompany::BackOffice。