(Java)软件包组织有最佳实践吗?[关闭]


201

不久前,我在这里看到一个有关Java包的细粒度组织的问题。例如,my.project.utilmy.project.factorymy.project.service,等。

我现在找不到它,所以我不妨问这个问题。

是否有关于Java包组织的最佳实践以及它们中包含哪些内容?

您如何在Java项目中组织类?

例如,我正在与几个人一起工作的一个项目有一个称为bean的软件包。它最初是一个包含简单bean的项目,但最终(由于经验不足和时间不足)(几乎)包含了所有内容。我通过将一些工厂类放入工厂包中(使用创建bean的静态方法的类)对它们进行了一些清理,但是我们还有其他一些类在执行业务逻辑,而其他一些类则在进行简单的处理(而不是使用业务逻辑),例如检索来自属性文件的代码消息。

感谢您的想法和意见。


74
我不同意这个问题的结尾。我不同意最佳实践问题几乎总是基于经验和观点,但是我不同意这些问题应在Stack Overflow中关闭。这是良好编程的关键,使用最佳实践,并利用这些意见和经验来找到最佳解决方案。请重新打开这个问题。
Cyntech

我建议您阅读以下内容: satisfice.com/blog/archives/5164。TL; DR ...“最佳实践”的整个想法被打破了。充其量它是严重的错误用语,最坏的情况是完全有害的。
Stephen C

Answers:


174

打包组织或打包结构通常是激烈的讨论。以下是一些简单的程序包命名和结构准则:

  • 遵循Java 包命名约定
  • 根据包的功能角色和业务角色来构建包
    • 根据其功能或模块细分软件包。例如 com.company.product.modulea
    • 进一步的细分可能基于您软件中的层。但是,如果程序包中只有几个类,那么不要太过分,那么将所有内容都包含在程序包中是有意义的。例如com.company.product.module.webcom.company.product.module.util
    • 除非急需,否则请避免过度进行结构设计,IMO避免为例外情况,工厂等单独包装。
  • 如果您的项目很小,请使用少量软件包简化它。例如com.company.product.modelcom.company.product.util等。
  • 看一下Apache项目上一些受欢迎的开源项目。了解他们如何针对各种规模的项目使用结构化。
  • 命名时还要考虑构建和分发(允许您将API或SDK分发到其他程序包中,请参阅servlet api)

经过一些实验和试验之后,您应该能够提出一个自己喜欢的结构。不要只拘泥于一种惯例,要接受变化。


感谢您的答复。这在很大程度上是我们试图涵盖的内容,但是很多无关的代码进入了我们的bean程序包,这正是我的问题所在。
Cyntech

2
我同意按功能打包最有意义。我曾经听过一个与公司办公室结构有关的比喻。在分层方法中,公司中每个级别的每个人都彼此坐在一起,即高管,经理,行政人员,员工/工人都坐在建筑物的不同部分中。这种结构可能不如“功能”有组织的方法有效。也就是说,如果销售主管与销售经理一起坐在一起,而销售经理与所有销售经理一起坐在一起的销售员工一起。这样组织时,可以在部门之间提供更好的凝聚力。
alex

同意你的观点。有时,要在公司获得的产品被出售时,要突出强调包装中公司名称的一点。管理层想要删除公司名称。那可能是开销。
Tushar D

182

按功能而不是按模式或实现角色来组织软件包。我认为包像:

  • beans
  • factories
  • collections

错了。

我更喜欢例如:

  • orders
  • store
  • reports

所以我可以通过程序包可见性来隐藏实现细节。订单工厂应位于orders包装中,以便隐藏有关如何创建订单的详细信息。


10
这篇文章很好地说明了程序包的可见性。我从未见过Java包作用域的使用,但是正确的包结构可以使开发人员更好地利用它。
Jpnh

23
这是完全正确的,但是很少有开发人员这样做。包应为类的内聚集合,其中某些类仅在包内可见。这样可以最大程度地减少不应耦合的类之间的耦合,因为它们属于不同的功能。逐层打包方法没有利用打包可见性修改器,并且此类项目中的打包具有低内聚性和打包之间的高度耦合。
Nate Reed

你有这个例子吗?我正在使用Spring-MVC,因为Spring使用config xml,所以很难按功能/模块来组织它。
埃里克·黄

2
@onof我也按功能组织代码,但是所有功能共享的基类的最佳实践是什么?
Marc

我遵循第一种风格。但是现在在使用类时,我必须从一个程序包跳到另一个程序包。这确实是一个糟糕的经历。我现在改用第二种风格,因为我认为一起学习相关课程会更容易。
M.kazem Akhgary


21

我更喜欢要素而不是图层,但是我想这取决于您的项目。考虑一下你的力量:

  • 依赖性
    尝试最小化程序包的依赖性,尤其是功能之间的依赖性。如有必要,提取API。
  • 团队组织
    在某些组织中,团队在要素上工作,而在另一些层次中。这会影响代码的组织方式,使用代码形式化API或鼓励合作。
  • 部署和版本控制
    将所有内容放到模块中可使部署和版本控制更简单,但错误修复更困难。拆分事物可以实现更好的控制,可伸缩性和可用性。
  • 响应变更
    井井有条的代码要比大团糟容易得多。
  • 大小(人员和代码行)
    越大,需要的形式越正式/标准化。
  • 重要性/质量
    一些代码比其他代码更重要。API应该比实施更稳定。因此,需要将其清楚地分开。
  • 抽象级别和入口点
    外部人员应该有可能知道代码的含义,以及从查看包树的位置开始阅读。

例:

com/company/module
  + feature1/
    - MainClass          // The entry point for exploring
    + api/               // Public interface, used by other features
    + domain/
      - AggregateRoot
      + api/             // Internal API, complements the public, used by web
      + impl/ 
    + persistence/       
    + web/               // presentation layer 
    + services/          // Rest or other remote API 
    + support/            
  + feature2/
  + support/             // Any support or utils used by more than on feature
    + io
    + config
    + persistence
    + web

这只是一个例子。这是很正式的。例如,它为feature1定义了2个接口。通常这不是必需的,但是如果不同的人使用不同的方法可能是个好主意。您可以让内部API扩展公共范围。

我不喜欢'impl'或'support'名称,但是它们有助于将次要的内容与重要的内容(域和API)分开。说到命名,我喜欢尽可能具体。如果您有一个名为“ utils”的包,其中包含20个类,请StringUtils转到support / string,HttpUtilsupport / http等。


13

是否有关于Java包组织的最佳实践以及它们中包含哪些内容?

真的不是。有很多想法和意见,但是真正的“最佳实践”是使用您的常识!

(请阅读“ 无最佳实践”,以获取有关“最佳实践”及其推广人员的观点。)

但是,有一个原则可能已被广泛接受。包的结构应反映应用程序的(非正式)模块结构,并且您应力求最小化(或理想情况下完全避免)模块之间的任何循环依赖关系。

(包/模块中的类之间的循环依赖关系很好,但是包间的循环往往使您难以理解应用程序的体系结构,并且可能成为代码重用的障碍。特别是,如果您使用Maven,则会发现该循环包之间/模块间的依赖性意味着整个相互联系的混乱必须是一个Maven工件。)

我还要补充一点,那里一个包名广为接受的最佳实践。那就是您的软件包名称应以相反的顺序以您组织的域名开头。如果遵循此规则,则可以减少因您的(完整)类名与其他人的名字冲突而引起问题的可能性。


9

我见过有人提倡“按功能打包”而不是“按层打包”,但是多年来我使用了很多方法,发现“按层打包”比“按功能打包”要好得多。

除此之外,我发现一种混合策略:“按模块打包,然后按要素打包”策略在实践中非常有效,因为它具有“按要素打包”的许多优点:

  • 促进可重用框架(具有模型和UI方面的库)的创建
  • 允许即插即用的层实现-对于“按功能打包”几乎是不可能的,因为它将层实现放置在与模型代码相同的包/目录中。
  • 还有很多...

我在这里详细解释:Java包名称结构和组织,但是我的标准包结构是:

revdomain.moduleType.moduleName.layer。[layerImpl] .feature.subfeatureN.subfeatureN + 1 ...

哪里:

revdomain反向域,例如com.mycompany

moduleType [app * | framework | util]

moduleName例如myAppName(如果模块类型为应用程序)或“财务”(如果其为会计框架)

[模型| ui |持久性|安全性等]

layerImpl,例如,wicket,jsp,jpa,jdo,hibernate(注意:如果图层是模型,则不使用)

功能,例如财务

子功能N,例如会计

子功能N + 1,例如折旧

*有时,如果moduleType是应用程序,则省略“ app”,但是将其放置在其中会使包结构在所有模块类型之间保持一致。


5

我不了解打包组织的标准做法。我通常会创建涵盖一些合理范围的软件包,但是我可以在一个项目中进行区分。例如,我当前正在处理的一个个人项目有一个专用于我的自定义UI控件的程序包(将类归类为swing类)。我有一个专门用于数据库管理的程序包,有一个我创建的一组侦听器/事件的程序包,依此类推。

另一方面,我有一个同事为他所做的几乎所有工作创建了一个新程序包。他想要的每个不同的MVC都有自己的程序包,而且似乎MVC集是允许在同一程序包中的类的唯一分组。我记得有一次他有5个不同的程序包,每个程序包都包含一个类。我认为他的方法有点极端(当我们根本无法处理时,团队迫使他减少了包裹数),但是对于非平凡的应用程序,则将所有内容都放在同一包裹中。这是您和您的队友必须自己寻找的平衡点。

您可以做的一件事就是尝试后退并思考:如果您是该项目的新成员,或者您的项目以开放源代码或API的形式发布,那么找到所需内容有多么容易/困难?因为对我来说,这就是我真正想要的东西:组织。与我将文件存储在计算机上的文件夹中的方式类似,我希望能够再次查找它们而不必搜索我的整个驱动器。我希望能够找到所需的类,而不必搜索包中所有类的列表。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.