Perl 模块层次结构和组合

Perl modules hierarchy and composition

关于 Perl 的阅读越来越多,我开始怀疑我在当前项目中如何组织我的模块。

我有一个主命名空间 - 我们称它为 "MyProject"。

在这个项目中,基础数据是图表,其中每个对象都有一个 class。对象与关系相关联。对象和关系都可以有属性。

项目的一部分我使用模型来验证这些图表。 所以我有一个模型 class,它由 class Class、关系和属性的对象组成。

Classes Class,关系和属性仅供 class 模型使用,因此按如下方式组织模块对我来说很有意义:

但我开始认为,只有当我敢于在 CPAN 中发布我项目的部分内容时,这对我才有意义。我想人们会相信 Class,Relation 和 Attribute 是继承 Model 而不是组合它。

所以:我应该这样重新组织我的模块吗:

或者可以通过附加名称表明 Class、关系和属性是模型的一部分?

我的问题:在组合方面,目前认为模块组织和命名的最佳实践是什么?

Cross-posted at Perlmonks

您的担心是正确的。通常,包由 inclusioninheritance 命名。我要编一个更现实的例子。假设我们正在建立一个在线商店。

包容

您首先为您的项目选择一个命名空间。在商业世界中,您经常会看到以公司名称开头的名称空间,以区分专有模块和 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。