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

时间:2023-05-05
本文介绍了您在 Java 项目中使用什么策略来命名包,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

限时送ChatGPT账号..

我不久前就想到了这个问题,最近它又出现了,因为我的商店正在开发它的第一个真正的 Java 网络应用程序.

I thought about this awhile ago and it recently resurfaced as my shop is doing its first real Java web app.

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

As an intro, I see two main package naming strategies. (To be clear, I'm not referring to the whole 'domain.company.project' part of this, I'm talking about the package convention beneath that.) Anyway, the package naming conventions that I see are as follows:

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

  1. Functional: Naming your packages according to their function architecturally rather than their identity according to the business domain. Another term for this might be naming according to 'layer'. So, you'd have a *.ui package and a *.domain package and a *.orm package. Your packages are horizontal slices rather than vertical.

很多比逻辑命名更常见.事实上,我相信我从未见过或听说过这样做的项目.这当然让我怀疑(有点像认为你已经想出了一个解决 NP 问题的方法),因为我不是很聪明,而且我认为每个人都必须有充分的理由这样做.另一方面,我不反对人们只是想念房间里的大象并且我从来没有听到过真正的论据支持以这种方式命名包.这似乎是事实上的标准.

This is much more common than logical naming. In fact, I don't believe I've ever seen or heard of a project that does this. This of course makes me leery (sort of like thinking that you've come up with a solution to an NP problem) as I'm not terribly smart and I assume everyone must have great reasons for doing it the way they do. On the other hand, I'm not opposed to people just missing the elephant in the room and I've never heard a an actual argument for doing package naming this way. It just seems to be the de facto standard.

逻辑:根据业务域标识命名您的包,并将与该垂直功能切片有关的每个类放入该包中.

Logical: Naming your packages according to their business domain identity and putting every class that has to do with that vertical slice of functionality into that package.

正如我之前提到的,我从未见过或听说过这个,但这对我来说很有意义.

I have never seen or heard of this, as I mentioned before, but it makes a ton of sense to me.

  1. 我倾向于垂直而不是水平地接近系统.我想进去开发订单处理系统,而不是数据访问层.显然,我很有可能会在该系统的开发中触及数据访问层,但关键是我不这么认为.当然,这意味着当我收到变更单或想要实现一些新功能时,不必为了找到所有相关类而在一堆包中四处寻找会很好.相反,我只是查看 X 包,因为我所做的与 X 有关.

  1. I tend to approach systems vertically rather than horizontally. I want to go in and develop the Order Processing system, not the data access layer. Obviously, there's a good chance that I'll touch the data access layer in the development of that system, but the point is that I don't think of it that way. What this means, of course, is that when I receive a change order or want to implement some new feature, it'd be nice to not have to go fishing around in a bunch of packages in order to find all the related classes. Instead, I just look in the X package because what I'm doing has to do with X.

从开发的角度来看,我认为让你的包记录你的业务领域而不是你的架构是一个重大的胜利.我觉得域几乎总是系统中更难理解的部分,因为系统的架构,特别是在这一点上,在其实现中几乎变得平凡.事实上,我可以使用这种类型的命名约定并立即从包的命名中知道它处理订单、客户、企业、产品等的系统,这似乎非常方便.

From a development standpoint, I see it as a major win to have your packages document your business domain rather than your architecture. I feel like the domain is almost always the part of the system that's harder to grok where as the system's architecture, especially at this point, is almost becoming mundane in its implementation. The fact that I can come to a system with this type of naming convention and instantly from the naming of the packages know that it deals with orders, customers, enterprises, products, etc. seems pretty darn handy.

这似乎可以让您更好地利用 Java 的访问修饰符.这使您可以更清晰地将接口定义到子系统中,而不是系统的层中.因此,如果您有一个希望透明持久化的订单子系统,理论上您可以通过不必在 dao 层中为其持久性类创建公共接口,而是将 dao 类包装在只有它处理的类.显然,如果你想公开这个功能,你可以为它提供一个接口或者将它公开.通过将系统功能的垂直部分拆分到多个包中,您似乎失去了很多.

It seems like this would allow you to take much better advantage of Java's access modifiers. This allows you to much more cleanly define interfaces into subsystems rather than into layers of the system. So if you have an orders subsystem that you want to be transparently persistent, you could in theory just never let anything else know that it's persistent by not having to create public interfaces to its persistence classes in the dao layer and instead packaging the dao class in with only the classes it deals with. Obviously, if you wanted to expose this functionality, you could provide an interface for it or make it public. It just seems like you lose a lot of this by having a vertical slice of your system's features split across multiple packages.

我想我可以看到的一个缺点是它确实使剥离图层变得更加困难.而不是仅仅删除或重命名一个包,然后用另一种技术将一个新的包放到适当的位置,您必须进入并更改所有包中的所有类.但是,我认为这没什么大不了的.这可能是由于缺乏经验,但我不得不想象,与您在系统中进入和编辑垂直特征切片的次数相比,您更换技术的次数相形见绌.

I suppose one disadvantage that I can see is that it does make ripping out layers a little bit more difficult. Instead of just deleting or renaming a package and then dropping a new one in place with an alternate technology, you have to go in and change all of the classes in all of the packages. However, I don't see this is a big deal. It may be from a lack of experience, but I have to imagine that the amount of times you swap out technologies pales in comparison to the amount of times you go in and edit vertical feature slices within your system.

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

So I guess the question then would go out to you, how do you name your packages and why? Please understand that I don't necessarily think that I've stumbled onto the golden goose or something here. I'm pretty new to all this with mostly academic experience. However, I can't spot the holes in my reasoning so I'm hoping you all can so that I can move on.

推荐答案

对于封装设计,我先按层划分,然后按其他功能划分.

For package design, I first divide by layer, then by some other functionality.

还有一些额外的规则:

  1. 层从最一般(底部)到最具体(顶部)堆叠
  2. 每一层都有一个公共接口(抽象)
  3. 一层只能依赖另一层的公共接口(封装)
  4. 一个层只能依赖于更通用的层(从上到下的依赖关系)
  5. 一个层最好依赖于它正下方的层

因此,例如,对于 Web 应用程序,您的应用程序层中可能有以下层(从上到下):

So, for a web application for example, you could have the following layers in your application tier (from top to bottom):

  • 表示层:生成将在客户端层中显示的 UI
  • 应用层:包含特定于应用的逻辑,有状态
  • 服务层:按域对功能进行分组,无状态
  • 集成层:提供对后端层(db、jms、email、...)的访问

对于生成的包布局,这些是一些附加规则:

For the resulting package layout, these are some additional rules:

  • 每个包名的根是<prefix.company>.<appname>.<layer>
  • 层的接口进一步按功能划分:<root>.<logic>
  • 层的私有实现以私有为前缀:<root>.private

这是一个示例布局.

表示层按视图技术划分,并且可选地按(组)应用程序划分.

The presentation layer is divided by view technology, and optionally by (groups of) applications.

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
...

服务层分为业务领域,受后端层领域逻辑的影响.

The service layer is divided into business domains, influenced by the domain logic in a backend tier.

com.company.appname.service.clientservice
com.company.appname.service.internal.jmsclientservice
com.company.appname.service.internal.xmlclientservice
com.company.appname.service.productservice
...

集成层分为技术"和访问对象.

The integration layer is divided into 'technologies' and access objects.

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
...

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

Advantages of separating packages like this is that it is easier to manage complexity, and it increases testability and reusability. While it seems like a lot of overhead, in my experience it actually comes very natural and everyone working on this structure (or similar) picks it up in a matter of days.

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

Why do I think the vertical approach is not so good?

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

In the layered model, several different high-level modules can use the same lower-level module. For example: you can build multiple views for the same application, multiple applications can use the same service, multiple services can use the same gateway. The trick here is that when moving through the layers, the level of functionality changes. Modules in more specific layers don't map 1-1 on modules from the more general layer, because the levels of functionality they express don't map 1-1.

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

When you use the vertical approach for package design, i.e. you divide by functionality first, then you force all building blocks with different levels of functionality into the same 'functionality jacket'. You might design your general modules for the more specific one. But this violates the important principle that the more general layer should not know about more specific layers. The service layer for example shouldn't be modeled after concepts from the application layer.

这篇关于您在 Java 项目中使用什么策略来命名包,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:java包名为什么要小写? 下一篇:如何使用 javac 编译 java 包结构

相关文章