(Java)包组织有最佳实践吗? [关闭]
Posted
技术标签:
【中文标题】(Java)包组织有最佳实践吗? [关闭]【英文标题】:Are there best practices for (Java) package organization? [closed] 【发布时间】:2011-03-14 16:00:46 【问题描述】:不久前,我在这里看到一个关于 java 包的细粒度组织的问题。比如my.project.util
、my.project.factory
、my.project.service
等
我现在找不到,所以我也不妨问个问题。
关于 Java 中的包组织以及其中的内容是否有最佳实践?
您如何在 Java 项目中组织类?
例如,我正在与几个人合作的一个项目有一个名为 beans 的包。它开始是一个包含简单 bean 的项目,但最终(由于经验不足和缺乏时间)包含所有东西(几乎)。我通过将一些工厂类放在工厂包中(具有创建 bean 的静态方法的类)对它们进行了一些清理,但是我们还有其他执行业务逻辑的类和其他执行简单处理(不使用业务逻辑)的类,例如检索来自属性文件的代码消息。
感谢您的想法和意见。
【问题讨论】:
我不同意这个问题的结束。我不同意最佳实践问题几乎总是基于经验和意见,但是,我不同意这些问题应该在 Stack Overflow 上结束。这是良好编程的关键,使用最佳实践并使用这些意见和经验找到最佳解决方案。请重新打开这个问题。 我建议您阅读以下内容:satisfice.com/blog/archives/5164。 TL; DR ...“最佳实践”的整个想法被打破了。充其量是一个严重的误称,在最坏的情况下它是完全有害的。 【参考方案1】:简答:每个模块/功能一个包,可能带有子包。将密切相关的东西放在同一个包中。避免包之间的循环依赖。
长答案:I agree with most of this article
【讨论】:
子包破坏封装。一个“子包”本身就是一个完全独立的包 链接已损坏。【参考方案2】:我不知道包组织的标准做法。我通常创建涵盖一些相当广泛的包,但我可以在项目中区分。例如,我目前正在处理的一个个人项目有一个专用于我的自定义 UI 控件的包(全是子类化 swing 类的类)。我有一个专门用于数据库管理的包,我有一个用于我创建的一组侦听器/事件的包,等等。
另一方面,我让一位同事为他所做的几乎所有事情创建了一个新包。他想要的每个不同的 MVC 都有自己的包,而且似乎 MVC 集是唯一允许在同一个包中的类分组。我记得有一次他有 5 个不同的包,每个包都有一个类。我认为他的方法有点极端(当我们根本无法处理时,团队强迫他减少他的包数),但对于一个不平凡的应用程序,将所有东西放在同一个包中也是如此。这是你和你的队友必须自己找到的平衡点。
您可以做的一件事是尝试退后一步思考:如果您是该项目的新成员,或者您的项目是作为开源或 API 发布的,那么找到您想要的内容是多么容易/难想?因为对我来说,这就是我真正想要的包:组织。与我将文件存储在计算机上的文件夹中的方式类似,我希望能够再次找到它们而无需搜索整个驱动器。我希望能够找到我想要的类,而不必搜索包中所有类的列表。
【讨论】:
【参考方案3】:关于 Java 中的包组织以及其中的内容是否有最佳实践?
不是真的没有。有很多想法,很多意见,但真正的“最佳实践”是运用你的常识!
(请阅读No best Practices 了解“最佳实践”和推广他们的人的观点。)
但是,有一个原则可能被广泛接受。您的包结构应该反映您的应用程序的(非正式)模块结构,并且您应该致力于最小化(或理想地完全避免)模块之间的任何循环依赖关系。
(包/模块中的类之间的循环依赖关系很好,但包间循环往往会使您难以理解应用程序的架构,并且可能成为代码重用的障碍。特别是,如果您使用 Maven,您将发现循环的包间/模块间依赖意味着整个互连的混乱必须是一个 Maven 工件。)
我还应该补充一点, 是一种被广泛接受的包名称最佳实践。那就是你的包名应该以你组织的域名以相反的顺序开始。如果您遵循此规则,您可以减少因(完整)类名与其他人的冲突而导致问题的可能性。
【讨论】:
【参考方案4】:我更喜欢层之前的功能,但我想这取决于你的项目。考虑你的力量:
依赖关系 尝试最小化包依赖关系,尤其是功能之间。 必要时提取 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,将 HttpUtil
移动到 support/http 等等。
【讨论】:
【参考方案5】:我按功能组织包,而不是按模式或实现角色。我认为像这样的包:
beans
factories
collections
错了。
我更喜欢,例如:
orders
store
reports
所以我可以通过包可见性隐藏实现细节。订单工厂应位于 orders
包中,因此隐藏了有关如何创建订单的详细信息。
【讨论】:
这篇文章很好地说明了包的可见性。我从未见过使用 Java 包范围,但正确的包结构可以让开发人员更好地利用它。 这完全正确,但很少有开发人员这样做。包应该是类的内聚集合,其中一些仅在包中可见。这将最大限度地减少不应耦合的类之间的耦合,因为它们与不同的特性有关。逐层包的方法,没有利用包可见性修饰符,这样的项目中的包内聚度低,包之间的耦合度高。 你有这方面的例子吗?我正在使用 Spring-MVC,我发现很难按功能/模块来组织它,因为 spring 使用配置 xml。 @onof 我也按功能组织我的代码,但是所有功能共享的基类的最佳实践是什么? 我遵循第一种风格。但是现在我在处理类时必须从一个包跳到另一个包。这真的是一个糟糕的体验。我现在正在切换到第二种风格,因为我认为一起学习相关课程会更容易。【参考方案6】:包组织或包结构通常是一个激烈的讨论。下面是一些关于包命名和结构的简单指南:
关注javapackage naming conventions 根据功能角色和业务角色构建您的包 根据功能或模块分解您的包。例如com.company.product.modulea
进一步细分可能基于您软件中的层。但是,如果您的包中只有几个类,请不要太过分,那么将所有东西都放在包中是有意义的。例如com.company.product.module.web
或 com.company.product.module.util
等。
避免过度结构化,IMO 避免对异常、工厂等进行单独包装,除非有迫切需要。
如果您的项目很小,请使用几个包保持简单。例如com.company.product.model
和com.company.product.util
等
在Apache projects 上查看一些流行的开源项目。了解他们如何将结构化用于各种规模的项目。
命名时还要考虑构建和分发(允许您将 api 或 SDK 分发到不同的包中,请参阅 servlet api)
经过一些实验和试验,您应该能够想出一个您感到满意的结构。不要拘泥于一种惯例,要对变化持开放态度。
【讨论】:
感谢您的回复。这在很大程度上是我们试图包含的内容,但是很多不相关的代码进入了我们的 beans 包,这就是我的问题的来源。 我同意按功能打包是最有意义的。我曾经听过一个与公司办公室结构有关的类比。在分层方法中,公司中每个级别的每个人都将彼此坐在一起,即高管、经理、管理员、员工/工人都坐在建筑物的不同部分。这种结构可能不如“特征”组织方法有效。 IE。如果销售主管与销售经理坐在一起,而销售经理与销售员工坐在一起,而销售员工都与销售管理员坐在一起。当以这种方式组织时,这可以提高部门之间的凝聚力。 同意你的观点。有时需要在包装中突出显示公司名称的一点,公司获得的产品被出售。管理层想删除公司名称。这可能是开销。【参考方案7】:我见过一些人提倡“逐层封装”而不是“逐层封装”,但多年来我使用了很多方法,发现“逐层封装”比“逐层封装”要好得多。
此外,我发现混合:“按模块打包,层然后功能”策略在实践中效果非常好,因为它具有“按功能打包”的许多优点:
促进创建可重用框架(具有两种模型的库 和 UI 方面) 允许即插即用层实现 - 使用“按功能打包”几乎不可能,因为它将层实现与模型代码放在相同的包/目录中。 还有更多...我在这里深入解释:Java Package Name Structure and Organization 但我的标准包结构是:
revdomain.moduleType.moduleName.layer.[layerImpl].feature.subfeatureN.subfeatureN+1...
地点:
revdomain 反向域,例如com.mycompany
moduleType [app*|framework|util]
模块名称 例如如果模块类型是应用程序,则为 myAppName;如果其为会计框架,则为“财务”
层 [model|ui|persistence|security etc.,]
layerImpl 例如,wicket、jsp、jpa、jdo、hibernate(注意:如果 layer 是模型,则不使用)
功能 例如,金融
subfeatureN 例如,会计
subfeatureN+1 例如,折旧
*如果 moduleType 是一个应用程序,有时会省略“app”,但将它放在那里可以使所有模块类型的包结构保持一致。
【讨论】:
以上是关于(Java)包组织有最佳实践吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章