我应该如何构造Java应用程序,将类放在哪里?

时间:2020-03-05 18:38:54  来源:igfitidea点击:

首先,我知道如何构建Java应用程序。但是我总是对在哪里上课感到困惑。支持以严格面向领域的方式组织软件包的支持者,其他支持者则按层分开。

我本人一直有问题

  • 命名,
  • 放置

所以,

  • 我们将域特定的常数放在哪里(这种类的最佳名称是什么)?
  • 我们在哪里放置基础结构和领域特定的东西的类(例如,我有一个FileStorageStrategy类,该文件将文件存储在数据库中,或者存储在数据库中)?
  • 在哪里放置例外?
  • 有什么我可以参考的标准吗?

解决方案

回答

类名应始终是描述性的,并且不言自明。如果我们对类负责多个领域,则应该将其重构。

同样对于包裹。应按责任范围对它们进行分组。每个域都有其自己的例外。

通常不要流汗,直到它变得势不可挡和肿胀为止。然后坐下来,不编写代码,只重构类,定期编译以确保一切正常。然后像以前一样继续。

回答

使用软件包将相关功能分组在一起。

通常,在包树的顶部是域名(" com.domain.subdomain")被反转以确保唯一性,然后通常会为应用程序提供一个包。然后按相关区域进行细分,因此FileStorageStrategy可能会输入例如com.domain.subdomain.myapp.storage,然后com.domain.subdomain.myapp中可能会有特定的实现/子类/其他内容。 .storage.filecom.domain.subdomain.myapp.storage.database。这些名称可能会很长,但是import`会将它们全部保留在文件的顶部,而IDE也可以帮助管理它们。

异常通常与引发它们的类放在同一个包中,因此,如果我们拥有FileStorageException,它将与FileStorageStrategy放在同一个包中。同样,定义常量的接口将位于同一包中。

并没有真正的标准,只是使用常识,如果一切都太混乱了,请重构!

回答

过去,如果我要扩展课程,我会做的一件事,我将尝试遵循他们的约定。例如,当使用Spring Framework时,我会将MVC控制器类放在一个名为com.mydomain.myapp.web.servlet.mvc的程序包中
如果我不扩展某些内容,那么我只会选择最简单的内容。 com.mydomain.domain用于域对象(尽管如果我们有大量域对象,则此程序包可能会有些笨拙)。
对于特定于域的常量,我实际上将它们作为公共常量放在最相关的类中。例如,如果我有一个" Member"类,并且具有最大的成员名称长度常量,则将其放在Member类中。一些商店创建了一个单独的Constants类,但是我看不到将无关的数字和字符串归为一个类的价值。我已经看到其他一些商店尝试通过创建SEPARATE Con​​stants类来解决此问题,但这似乎浪费时间,结果也令人困惑。使用此设置,具有多个开发人员的大型项目将在各处复制常量。

回答

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

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

查看符合我们所见内容的课程

控制核心功能类

实用任何杂项。使用的类(通常是静态函数)

等等。

回答

我想保持简单,不要过分考虑。不要过度抽象和过多分层。只要保持整洁,随着它的增长,对其进行重构就变得微不足道了。 IDE的最佳功能之一就是重构,所以为什么不使用它并为解决与应用程序相关的问题(而不是像代码组织这样的元问题)节省脑力。

回答

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

/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在同一个域类包中。

回答

我真的很喜欢Maven的标准目录布局。

我的主要想法之一是拥有两个源根,一个用于生产代码,一个用于测试代码,如下所示:

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

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

好处:

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

关于类放置和包的一条经验法则:

一般来说,结构良好的项目将没有循环依赖。了解何时它们不好(什么时候不好),并考虑使用诸如JDepend或者SonarJ之类的工具来消除它们。

回答

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

回答

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

在老式的计算机科学模块化编程意义上,将顶层软件包用于应用程序模块应该是显而易见的。但是,在我从事的大多数项目中,我们最终都会忘记这样做,最终会遇到一堆没有顶层结构的软件包。这种反模式通常将自己显示为"侦听器"或者"动作"之类的程序包,这些程序将原本无关的类组合在一起,仅仅是因为它们恰好实现相同的接口。

在模块内或者在小型应用程序中,将包用于应用程序层。根据体系结构,可能的软件包包括以下内容:

  • 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"一样被使用)

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

回答

在我工作的地方,我们正在使用Maven 2,我们的项目有一个很好的原型。目标是获得良好的关注点分离,因此我们使用多个模块(每个应用程序"层"一个)定义了一个项目结构:
通用:其他层使用的通用代码(例如,i18n)
实体:域实体
仓库:此模块包含daos接口和实现
services-intf:服务接口(例如UserService等)
services-impl:服务的实现(例如UserServiceImpl)
网络:与网络内容相关的所有信息(例如,css,jsps,jsf页面等)
ws:Web服务

每个模块都有其自己的依赖项(例如,存储库可能具有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存储库中,然后在另一个项目中重用)
  • 项目各部分的最大独立性

我知道这并不能回答所有问题,但是我认为这可以使我们走上正确的道路,并可能对其他人有用。