(Java) 包组织有最佳实践吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3226282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are there best practices for (Java) package organization?
提问by Cyntech
A little while ago, I saw a question answered here regarding the fine-grained organization of java packages. For example, my.project.util
, my.project.factory
, my.project.service
, etc.
不久前,我看到这里回答了一个关于 java 包的细粒度组织的问题。例如my.project.util
,my.project.factory
、my.project.service
、 等。
I can't find it now, so I may as well ask the question.
我现在找不到了,所以我也可以问这个问题。
Are there best practices with regards to the organization of packages in Java and what goes in them?
是否有关于 Java 包组织的最佳实践以及它们的内容?
How do you organize your classes in your Java project?
您如何组织 Java 项目中的类?
For instance, a project I'm working on with a few people has a package called beans. It started out being a project containing simple beans, but has ended up (through poor experience and lack of time) containing everything (almost). I've cleaned them up a little, by putting some factory classes in a factory package (classes with static methods that create beans) but we have other classes that do business logic and others that do simple processing (not with business logic) like retrieving a message for a code from a properties file.
例如,我正在与几个人合作的一个项目有一个名为 beans 的包。它开始是一个包含简单 bean 的项目,但最终(由于糟糕的经验和缺乏时间)包含所有内容(几乎)。我已经清理了一点,通过将一些工厂类放在工厂包中(具有创建 bean 的静态方法的类),但我们还有其他类执行业务逻辑和其他执行简单处理(不使用业务逻辑)的类,例如检索来自属性文件的代码消息。
Your thoughts and comments are appreciated.
感谢您的想法和评论。
采纳答案by naikus
Package organization or package structuring is usually a heated discussion. Below are some simple guidelines for package naming and structuring:
包组织或包结构通常是一个激烈的讨论。下面是一些包命名和结构的简单指南:
- Follow java package naming conventions
- Structure your packages according to their functional role as well as their business role
- Break down your packages according to their functionality or modules. e.g.
com.company.product.modulea
- Further break down could be based on layers in your software. But don't go overboard if you have only few classes in the package, then it makes sense to have everything in the package. e.g.
com.company.product.module.web
orcom.company.product.module.util
etc. - Avoid going overboard with structuring, IMO avoid separate packaging for exceptions, factories, etc. unless there's a pressing need.
- Break down your packages according to their functionality or modules. e.g.
- If your project is small, keep it simple with few packages. e.g.
com.company.product.model
andcom.company.product.util
, etc. - Take a look at some of the popular open source projects out there on Apache projects. See how they use structuring, for various sized projects.
- Also consider build and distribution when naming ( allowing you to distribute your api or SDK in a different package, see servlet api)
- 遵循java包命名约定
- 根据功能角色和业务角色构建您的包
- 根据它们的功能或模块分解你的包。例如
com.company.product.modulea
- 进一步细分可能基于您软件中的层。但是,如果您的包中只有几个类,请不要太过分,那么将所有内容都包含在包中是有意义的。例如
com.company.product.module.web
或com.company.product.module.util
等。 - 避免结构化过度,IMO 避免为异常、工厂等单独包装,除非有迫切需要。
- 根据它们的功能或模块分解你的包。例如
- 如果您的项目很小,请使用几个包保持简单。例如
com.company.product.model
和com.company.product.util
等。 - 看看Apache 项目上的一些流行的开源项目。了解他们如何为各种规模的项目使用结构化。
- 命名时还要考虑构建和分发(允许您在不同的包中分发 api 或 SDK,请参阅 servlet api)
After a few experiments and trials you should be able to come up with a structuring that you are comfortable with. Don't be fixated on one convention, be open to changes.
经过几次实验和试验后,您应该能够想出一个您满意的结构。不要执着于一个约定,要对变化持开放态度。
回答by Brian S
I'm not aware of standard practices for package organization. I generally create packages that cover some reasonably broad spectrum, but I can differentiate within a project. For example, a personal project I'm currently working on has a package devoted to my customized UI controls (full of classes subclassing swing classes). I've got a package devoted to my database management stuff, I've got a package for a set of listeners/events that I've created, and so on.
我不知道包组织的标准做法。我通常会创建涵盖一些相当广泛的范围的包,但我可以在一个项目中进行区分。例如,我目前正在处理的一个个人项目有一个专门用于我的自定义 UI 控件的包(充满了从 Swing 类继承的类)。我有一个专门用于我的数据库管理内容的包,我有一个用于我创建的一组侦听器/事件的包,等等。
On the other hand I've had a coworker create a new package for almost everything he did. Each different MVC he wanted got its own package, and it seemed a MVC set was the only grouping of classes allowed to be in the same package. I recall at one point he had 5 different packages that each had a single class in them. I think his method is a little bit on the extreme (and the team forced him to reduce his package count when we simply couldn't handle it), but for a nontrivial application, so would putting everything in the same package. It's a balance point you and your teammates have to find for yourself.
另一方面,我让一位同事为他所做的几乎所有事情创建了一个新包。他想要的每个不同的 MVC 都有自己的包,而且 MVC 集似乎是唯一允许在同一个包中的类分组。我记得有一次他有 5 个不同的包,每个包都有一个类。我认为他的方法有点极端(当我们根本无法处理时,团队强迫他减少他的包数),但对于一个重要的应用程序,将所有内容放在同一个包中也是如此。这是您和您的队友必须为自己找到的平衡点。
One thing you can do is try to step back and think: if you were a new member introduced to the project, or your project was released as open source or an API, how easy/difficult would it be to find what you want? Because for me, that's what I really want out of packages: organization. Similar to how I store files in folder on my computer, I expect to be able to find them again without having to search my entire drive. I excpect to be able to find the class I want without having to search the list of all classes in the package.
您可以做的一件事是尝试退后一步思考:如果您是项目的新成员,或者您的项目以开源或 API 的形式发布,那么找到您想要的东西有多么容易/困难?因为对我来说,这就是我真正想要的包:组织。与我在计算机上的文件夹中存储文件的方式类似,我希望能够再次找到它们,而无需搜索我的整个驱动器。我希望能够找到我想要的类,而不必搜索包中所有类的列表。
回答by onof
I organize packages by feature, not by patterns or implementation roles. I think packages like:
我按功能组织包,而不是按模式或实现角色。我认为像这样的包:
beans
factories
collections
beans
factories
collections
are wrong.
错了。
I prefer, for example:
我更喜欢,例如:
orders
store
reports
orders
store
reports
so I can hide implementation details through package visibility. Factory of orders should be in the orders
package so details about how to create an order are hidden.
所以我可以通过包可见性隐藏实现细节。订单工厂应在orders
包中,以便隐藏有关如何创建订单的详细信息。
回答by Stephen C
Are there best practices with regards to the organisation of packages in Java and what goes in them?
是否有关于 Java 包组织的最佳实践以及它们的内容?
Not really no. There are lots of ideas, and lots opinions, but "best practice" is to use your common sense!
不是真的没有。有很多想法,很多意见,但“最佳实践”是使用您的常识!
However, there is one principal that probably has broad acceptance. Your package structure should reflect your application's (informal) module structure, and you should aim to minimize (or ideally entirely avoid) any cyclic dependencies between modules.
然而,有一个原则可能被广泛接受。您的包结构应该反映您的应用程序的(非正式)模块结构,并且您应该致力于最小化(或理想情况下完全避免)模块之间的任何循环依赖关系。
(Cyclic dependencies between classes in a package / module are just fine, but inter-package cycles tend to make it hard understand your application's architecture, and can be a barrier to code reuse. In particular, if you use Maven you will find that cyclic inter-package / inter-module dependencies mean that the whole interconnected mess has to be one Maven artifact.)
(包/模块中的类之间的循环依赖很好,但是包间循环往往会使您难以理解应用程序的架构,并且可能成为代码重用的障碍。特别是,如果您使用 Maven,您会发现循环包间/模块间依赖意味着整个互连的混乱必须是一个 Maven 工件。)
I should also add that there isone widely accepted best practice for package names. And that is that your package names should start with your organization's domain name in reverse order. If you follow this rule, you reduce the likelihood of problems caused by your (full) class names clashing with other peoples'.
我还要补充一点,那里是一个包名广为接受的最佳实践。那就是您的包名称应该以相反的顺序以您组织的域名开头。如果你遵循这个规则,你就减少了由你的(完整的)类名与其他人的冲突引起的问题的可能性。
回答by Volksman
I've seen some people promote 'package by feature' over 'package by layer' but I've used quite a few approaches over many years and found 'package by layer' much better than 'package by feature'.
我看到有些人提倡“按功能打包”而不是“按层打包”,但多年来我使用了很多方法,发现“按层打包”比“按功能打包”要好得多。
Further to that I have found that a hybrid: 'package by module, layer then feature' strategy works extremely well in practice as it has many advantages of 'package by feature':
此外,我发现混合:“按模块打包,然后按功能打包”策略在实践中非常有效,因为它具有“按功能打包”的许多优点:
- Promotes creation of reusable frameworks (libraries with both model and UI aspects)
- Allows plug and play layer implementations - virtually impossible with 'package by feature' because it places layer implementations in same package/directory as model code.
- Many more...
- 促进可重用框架的创建(具有模型和 UI 方面的库)
- 允许即插即用层实现 - “按功能打包”几乎不可能,因为它将层实现与模型代码放在相同的包/目录中。
- 还有很多...
I explain in depth here: Java Package Name Structure and Organizationbut my standard package structure is:
我在这里深入解释:Java Package Name Structure and Organization但我的标准包结构是:
revdomain.moduleType.moduleName.layer.[layerImpl].feature.subfeatureN.subfeatureN+1...
revdomain.moduleType.moduleName.layer.[layerImpl].feature.subfeatureN.subfeatureN+1...
Where:
在哪里:
revdomainReverse domain e.g. com.mycompany
revdomain反向域,例如 com.mycompany
moduleType[app*|framework|util]
模块类型[app*|framework|util]
moduleNamee.g. myAppName if module type is an app or 'finance' if its an accounting framework
moduleName例如 myAppName 如果模块类型是应用程序或“财务”如果它是会计框架
layer[model|ui|persistence|security etc.,]
层[model|ui|persistence|security etc,]
layerImpleg., wicket, jsp, jpa, jdo, hibernate (Note: not used if layer is model)
layerImpl例如,wicket、jsp、jpa、jdo、hibernate(注意:如果层是模型,则不使用)
featureeg., finance
功能,例如,金融
subfeatureNeg., accounting
子功能N例如,会计
subfeatureN+1eg., depreciation
subfeatureN+1例如,折旧
*Sometimes 'app' left out if moduleType is an application but putting it in there makes the package structure consistent across all module types.
*如果 moduleType 是一个应用程序,有时会省略“app”,但将它放在那里可以使所有模块类型的包结构保持一致。
回答by Peter Tseng
Short answer: One package per module/feature, possibly with sub-packages. Put closely related things together in the same package. Avoid circular dependencies between packages.
简短回答:每个模块/功能一个包,可能带有子包。把密切相关的东西放在同一个包里。避免包之间的循环依赖。
Long answer: I agree with most of this article
长答案:我同意这篇文章的大部分内容
回答by ThomasGran
I prefer feature before layers, but I guess it depends on you project. Consider your forces:
我更喜欢图层之前的功能,但我想这取决于您的项目。考虑你的力量:
- Dependencies
Try minimize package dependencies, especially between features. Extract APIs if necessary. - Team organization
In some organizations teams work on features and in others on layers. This influence how code is organized, use it to formalize APIs or encourage cooperation. - Deployment and versioning
Putting everything into a module make deployment and versioning simpler, but bug fixing harder. Splitting things enable better control, scalability and availability. - Respond to change
Well organized code is much simpler to change than a big ball of mud. - Size(people and lines of code)
The bigger the more formalized/standardized it needs to be. - Importance/quality
Some code is more important than other. APIs should be more stable then the implementation. Therefore it needs to be clearly separated. - Level of abstraction and entry point
It should be possible for an outsider to know what the code is about, and where to start reading from looking at the package tree.
- 依赖性
尽量减少包依赖性,尤其是功能之间的依赖性。如有必要,提取 API。 - 团队组织
在一些组织中,团队在功能上工作,而在其他组织中则在层上工作。这会影响代码的组织方式,使用它来规范 API 或鼓励合作。 - 部署和版本控制
将所有内容放入一个模块中使部署和版本控制更简单,但错误修复更难。拆分事物可实现更好的控制、可扩展性和可用性。 - 响应变化
组织良好的代码比一团大泥球更容易改变。 - 规模(人和代码行)
越大,它就需要越正式/标准化。 - 重要性/质量
某些代码比其他代码更重要。API 应该比实现更稳定。因此需要明确区分。 - 抽象级别和入口点
外人应该可以知道代码是关于什么的,以及从查看包树开始阅读的地方。
Example:
例子:
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
This is just an example. It is quite formal. For example it defines 2 interfaces for feature1. Normally that is not required, but could be a good idea if used differently by different people. You may let the internal API extend the public.
这只是一个例子。这是相当正式的。例如,它为feature1定义了 2 个接口。通常这不是必需的,但如果不同的人使用不同的方式,这可能是一个好主意。您可以让内部 API 扩展公共。
I do not like the 'impl' or 'support' names, but they help separate the less important stuff from the important (domain and API). When it comes to naming I like to be as concrete as possible. If you have a package called 'utils' with 20 classes, move StringUtils
to support/string, HttpUtil
to support/http and so on.
我不喜欢“impl”或“support”名称,但它们有助于将不太重要的内容与重要的内容(域和 API)分开。在命名时,我喜欢尽可能具体。如果您有一个包含 20 个类的名为“utils”的包,请移至StringUtils
support/string、HttpUtil
support/http 等。