java - 你在 Java 项目中使用什么策略来命名包,为什么?

标签 java naming-conventions packages

关闭。这个问题是 opinion-based 。它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文来回答。

4年前关闭。



Improve this question




不久前我曾考虑过这个问题,最近它重新出现,因为我的商店正在开发第一个真正的 Java Web 应用程序。

作为介绍,我看到了两种主要的包命名策略。 (需要明确的是,我不是指整个“domain.company.project”部分,我指的是它下面的包约定。)无论如何,我看到的包命名约定如下:

  • 功能性:根据架构上的功能而不是根据业务领域的身份来命名包。 另一个术语可能是根据“层”命名。因此,您将拥有一个 *.ui 包和一个 *.domain 包以及一个 *.orm 包。您的包裹是水平切片而不是垂直切片。

    这比逻辑命名更常见。事实上,我相信我从未见过或听说过这样做的项目。这当然让我怀疑(有点像认为你已经想出了一个 NP 问题的解决方案),因为我不是很聪明,而且我认为每个人都必须有很好的理由按照他们的方式去做。另一方面,我并不反对人们只是想念房间里的大象,而且我从未听说过以这种方式进行包命名的实际争论。它似乎只是事实上的标准。
  • 逻辑:根据业务域标识 命名您的包,并将与该垂直功能切片有关的每个类放入该包中。

    正如我之前提到的,我从未见过或听说过这个,但这对我来说很有意义。
  • 我倾向于垂直而不是水平地接近系统。我想进去开发订单处理系统,而不是数据访问层。显然,我很有可能会在该系统的开发过程中接触数据访问层,但关键是我不这么认为。当然,这意味着当我收到变更单或想要实现一些新功能时,最好不必在一堆包中寻找所有相关类。相反,我只是查看 X 包,因为我所做的与 X 相关。
  • 从开发的角度来看,我认为让你的包记录你的业务领域而不是你的架构是一个重大的胜利。我觉得域几乎总是系统中更难理解的部分,因为系统的架构,尤其是在这一点上,在其实现中几乎变得平凡。事实上,我可以使用这种命名约定来到一个系统,并立即从包的命名中知道它处理订单、客户、企业、产品等,这似乎非常方便。
  • 似乎这样可以让您更好地利用 Java 的访问修饰符。这使您可以更清晰地将接口(interface)定义到子系统而不是系统层中。因此,如果您有一个希望透明持久化的订单子(monad)系统,那么理论上您可以永远不要让其他任何东西知道它是持久的,因为不必在 dao 层中为其持久化类创建公共(public)接口(interface),而是将 dao 类打包在只有它处理的类。显然,如果你想公开这个功能,你可以为它提供一个接口(interface)或公开它。通过将系统功能的垂直切片拆分到多个包中,您似乎失去了很多。
  • 我想我可以看到的一个缺点是它确实使剥离图层变得更加困难。不是简单地删除或重命名一个包,然后使用替代技术放置一个新的包,您必须进入并更改所有包中的所有类。但是,我不认为这有什么大不了的。这可能是由于缺乏经验,但我不得不想象,与您在系统中进入并编辑垂直特征切片的次数相比,您更换技术的次数相形见绌。

  • 所以我想你会问这个问题,你如何命名你的包,为什么?请理解,我不一定认为我在这里偶然发现了金鹅或其他东西。我对这一切都很陌生,主要是学术经验。但是,我无法发现我的推理中的漏洞,所以我希望你们都可以,这样我就可以继续前进。

    最佳答案

    对于包装设计,我首先按层划分,然后按其他一些功能划分。

    还有一些额外的规则:

  • 层从最一般(底部)到最具体(顶部)堆叠
  • 每层都有一个公共(public)接口(interface)(抽象)
  • 一层只能依赖另一层的公共(public)接口(interface)(封装)
  • 一个层只能依赖更通用的层(从上到下的依赖)
  • 一个层最好依赖于它正下方的层

  • 因此,例如,对于 Web 应用程序,您的应用程序层(从上到下)可以具有以下层:
  • 表示层:生成将在客户端层显示的 UI
  • 应用层:包含特定于应用的逻辑,有状态
  • 服务层:按域分组功能,无状态
  • 集成层:提供对后端层(db、jms、email 等)的访问

  • 对于生成的包布局,这些是一些额外的规则:
  • 每个包名的根是 <prefix.company>.<appname>.<layer>
  • 一层的接口(interface)按功能进一步拆分:<root>.<logic>
  • 层的私有(private)实现以私有(private)为前缀:<root>.private

  • 这是一个示例布局。

    表示层按 View 技术划分,并可选择按(组)应用程序划分。
    com.company.appname.presentation.internal
    com.company.appname.presentation.springmvc.product
    com.company.appname.presentation.servlet
    ...
    

    应用层分为用例。
    com.company.appname.application.lookupproduct
    com.company.appname.application.internal.lookupproduct
    com.company.appname.application.editclient
    com.company.appname.application.internal.editclient
    ...
    

    服务层被划分为业务域,受后端层中域逻辑的影响。
    com.company.appname.service.clientservice
    com.company.appname.service.internal.jmsclientservice
    com.company.appname.service.internal.xmlclientservice
    com.company.appname.service.productservice
    ...
    

    集成层分为“技术”和访问对象。
    com.company.appname.integration.jmsgateway
    com.company.appname.integration.internal.mqjmsgateway
    com.company.appname.integration.productdao
    com.company.appname.integration.internal.dbproductdao
    com.company.appname.integration.internal.mockproductdao
    ...
    

    像这样分离包的优点是更容易管理复杂性,并且增加了可测试性和可重用性。虽然这看起来像是很多开销,但根据我的经验,它实际上是很自然的,每个在这个结构(或类似结构)上工作的人都会在几天内把它捡起来。

    为什么我认为垂直方法不太好?

    在分层模型中,几个不同的高层模块可以使用同一个低层模块。例如:可以为同一个应用构建多个 View ,多个应用可以使用同一个服务,多个服务可以使用同一个网关。这里的诀窍是,在层级之间移动时,功能级别会发生变化。更具体层中的模块不会将 1-1 映射到来自更通用层的模块上,因为它们表达的功能级别不会映射 1-1。

    当您使用垂直方法进行包装设计时,即首先按功能划分,然后将具有不同功能级别的所有构建块强制放入相同的“功能夹克”中。您可以为更具体的模块设计通用模块。但这违反了更一般的层不应该知道更具体的层的重要原则。例如,服务层不应模仿应用层的概念。

    关于java - 你在 Java 项目中使用什么策略来命名包,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/533102/

    相关文章:

    java - 如何反转java中linkedhashmap中存储的 key

    java - 如何找到为 Spring boot 服务记录的请求的目标 URL

    java - 如何使用特殊字符在字符串中公开

    database - 非规范化字段的命名约定

    java - 简单但反复出现的命名问题

    linux - Linux更新相同的用途

    ubuntu - 无法安装 f.lux

    python - 设置 py2app 以运行 selenium

    java - Eclipse 避免 jmockit 换行

    asp.net-mvc - 命名 ASP.NET MVC 中存在的 3 种不同类型模型的约定是什么? ( Controller 输入、 Controller 输出和持久性)