我应该如何构建Java应用程序,在哪里放置我的类?

时间:2008-08-11 07:45:20

标签: java architecture

首先,我知道如何构建Java应用程序。但是我总是对我的课程放在哪里感到困惑。有支持者以严格的域名方式组织包,其他人按层次分开。

我自己总是遇到问题

  • 命名,
  • 放置

所以,

  1. 你在哪里放置你的域特定常量(这个类的最佳名称是什么)?
  2. 你在哪里为基础设施和特定领域的东西放置类(例如我有一个FileStorageStrategy类,它将文件存储在数据库中,或者存储在数据库中)?
  3. 在哪里放置例外?
  4. 我可以参考哪些标准?

10 个答案:

答案 0 :(得分:26)

我真的喜欢Maven的Standard Directory Layout

对我来说,一个关键的想法是有两个源根 - 一个用于生产代码,另一个用于测试代码,如下所示:

MyProject/src/main/java/com/acme/Widget.java
MyProject/src/test/java/com/acme/WidgetTest.java

(这里,src / main / java和src / test / java都是源根)。

优点:

  • 您的测试对您正在测试的类具有包(或“默认”)级别访问权限。
  • 您可以通过删除src / test / java作为源根目录,轻松地将生产源打包到JAR中。

关于课程安排和课程的一条经验法则:

一般而言,结构良好的项目将免于circular dependencies。了解它们何时不好(以及何时not),并考虑使用JDependSonarJ这样的工具来帮助您消除它们。

答案 1 :(得分:12)

我非常喜欢有组织的资源,所以我总是创建以下目录结构:

/src - for your packages & classes
/test - for unit tests
/docs - for documentation, generated and manually edited
/lib - 3rd party libraries
/etc - unrelated stuff
/bin (or /classes) - compiled classes, output of your compile
/dist - for distribution packages, hopefully auto generated by a build system

在/ src中我使用的是默认的Java模式:以您的域名开头的包名(org.yourdomain.yourprojectname)和反映您使用该类创建的OOP方面的类名(请参阅其他评论者)。常见的包名如 util model view events 也很有用。

我倾向于在自己的类中放置特定主题的常量,例如 SessionConstants ServiceConstants 在域类的同一个包中。

答案 2 :(得分:11)

我工作的地方,我们正在使用Maven 2,我们的项目有一个非常好的原型。目标是获得良好的关注点分离,因此我们使用多个模块(每个应用程序“层”一个)定义了一个项目结构:    - common:其他层使用的公共代码(例如,i18n)    - 实体:域实体    - 存储库:此模块包含daos接口和实现    - services-intf:服务的接口(例如,UserService,...)    - services-impl:服务的实现(例如,UserServiceImpl)    - web:关于网页内容的一切(例如,css,jsps,jsf页面......)    - ws:网络服务

每个模块都有自己的依赖项(例如,存储库可以有jpa),有些是项目范围的(因此它们属于公共模块)。不同项目模块之间的依赖关系明显区分(例如,Web层依赖于服务层但不了解存储库层)。

每个模块都有自己的基础包,例如,如果应用程序包是“com.foo.bar”,那么我们有:

com.foo.bar.common
com.foo.bar.entities
com.foo.bar.repositories
com.foo.bar.services
com.foo.bar.services.impl
...

每个模块都遵守标准的maven项目结构:

   src\
   ..main\java
     ...\resources
   ..test\java
     ...\resources

给定图层的单元测试很容易在\ src \ test下找到它们的位置......所有特定于域的东西都放在实体模块中。现在像FileStorageStrategy这样的东西应该进入存储库模块,因为我们不需要确切地知道实现是什么。在服务层,我们只知道存储库接口,我们不关心具体实现是什么(关注点分离)。

这种方法有许多优点:

  • 明确分离关注点
  • 每个模块都可以打包为jar(或者在Web模块的情况下是战争),因此可以更容易地重用代码(例如,我们可以将模块安装在maven存储库中并在另一个项目中重用)
  • 项目每个部分的最大独立性

我知道这并没有回答你所有的问题,但我认为这可能会让你走上正确的道路并且对其他人有用。

答案 3 :(得分:4)

类名应始终具有描述性和不言自明。如果您的班级有多个责任域,那么它们可能应该被重构。

同样适用于您的包裹。它们应按责任范围分组。每个域都有它自己的例外。

一般情况下,直到你达到压倒性和臃肿的程度时才会出汗。然后坐下来不要编码,只需重构课程,定期编译以确保一切正常。然后像以前一样继续。

答案 4 :(得分:3)

简短回答:根据模块绘制您的系统架构,并排绘制,每个模块垂直切成层(例如视图,模型,持久性)。然后使用像 com.mycompany.myapp.somemodule.somelayer 这样的结构,例如 com.mycompany.myapp.client.view com.mycompany.myapp.server.model

使用应用程序模块的顶级软件包,在modular programming的老式计算机科学意义上,应该是显而易见的。然而,在我参与的大多数项目中,我们最终忘记了这样做,并最终得到了一堆没有顶级结构的软件包。这种反模式通常表现为一个类似“侦听器”或“动作”的包,它们将其他不相关的类组合在一起只是因为它们碰巧实现了相同的接口。

在模块或小型应用程序中,使用应用程序层的包。可能的包包括以下内容,具体取决于架构:

  • com.mycompany.myapp.view
  • com.mycompany.myapp.model
  • com.mycompany.myapp.services
  • com.mycompany.myapp.rules
  • com.mycompany.myapp.persistence (或数据访问层的'dao')
  • com.mycompany.myapp.util (谨防使用它,好像它是'misc')

在每个层中,如果有很多,按类型对类进行分组是很自然的。这里常见的反模式是不必要地引入太多的包和级别的子包,以便每个包中只有几个类。

答案 5 :(得分:3)

我发现对单元测试非常有帮助的一件事是拥有myApp / src /以及myApp / test_src /目录。这样,我可以将单元测试放在与他们测试的类相同的包中,但是当我准备我的生产安装时,我可以轻松地排除测试用例。

答案 6 :(得分:3)

使用包将相关功能组合在一起。

通常,您的包树的顶部是您的域名反转(com.domain.subdomain)以保证唯一性,然后通常会有一个包为您的应用程序。然后按相关区域进行细分,以便FileStorageStrategy可以进入com.domain.subdomain.myapp.storage,然后在com.domain.subdomain.myapp.storage.filecom.domain.subdomain.myapp.storage.database中可能会有特定的实现/子类/任何内容。这些名称可能会很长,但import将它们全部保存在文件的顶部,IDE也可以帮助管理它们。

异常通常与抛出它们的类放在同一个包中,所以如果你有FileStorageException,那么它将与FileStorageStrategy放在同一个包中。同样,定义常量的接口也在同一个包中。

实际上没有任何标准,只是使用常识,如果一切都变得太乱,重构!

答案 7 :(得分:2)

我认为保持简单,不要过度思考。不要过度抽象和分层太多。保持整洁,随着它的发展,重构它是微不足道的。 IDE的最佳功能之一是重构,所以为什么不利用它来节省大脑能力来解决与你的应用相关的问题,而不是代码组织等元问题。

答案 8 :(得分:0)

我过去做过的一件事 - 如果我正在扩展课程,我会尝试遵循他们的惯例。例如,在使用Spring Framework时,我将把我的MVC Controller类放在一个名为com.mydomain.myapp.web.servlet.mvc的包中。 如果我没有扩展某些东西,我会选择最简单的东西。域对象的com.mydomain.domain(尽管如果你有大量的域对象,这个包可能会有点笨拙)。 对于特定于域的常量,我实际上将它们作为公共常量放在最相关的类中。例如,如果我有一个“Member”类并且最大成员名称长度不变,我将它放在Member类中。有些商店会创建一个单独的Constants类,但是我没有看到将不相关的数字和字符串整合到一个类中的价值。我已经看到其他一些商店试图通过创建SEPARATE常量类来解决这个问题,但这似乎是浪费时间,结果太混乱了。使用此设置,具有多个开发人员的大型项目将在整个地方复制常量。

答案 9 :(得分:0)

我喜欢将我的课程分解为彼此相关的包。

例如: 模型对于数据库相关的调用

查看处理所见内容的类

控制核心功能类

Util 任何misc。使用的类(通常是静态函数)