Spring目录结构与接口(最佳实践)

5
我目前正在编写我的第一个Spring应用程序(Spring boot + hibernate)。我查看了它们文档中的最佳实践目录结构,您可以在这里找到。它有道理。
问题1:
我有一个接口(或抽象类),有几个子类扩展了该接口,因此我只需要为父类添加一个@ Repository。 我决定这样做:
com
 +- example
     +- myapplication
         +- Application.java
         |
         +- message
         |   +- AbstractMessage.java
         |   +- IMessageRepository.java
         |   +- MessageRepositoryImpl.java
                +- messageTypeA
                |  +- messageTypeA.java
                |  +- messageTypeAService.java
                +- messageTypeB
                |  +- messageTypeB.java
                |  +- messageTypeBService.java

问题2:

现在我有一个新的实体需要保存,名为Group。那么我可以在与Message同级别的目录中添加一个Group目录。然而,这个Group实际上是Message的一部分(逻辑上),因此如果它是同一个message目录的一部分,这将是有意义的(唯一的原因是以这种方式保存它们更容易推导出分析)。此外,我甚至使用相同的MessageRepository来保存它(我只是添加了第二个方法到接口中,如下所示:)。

public interface MessageRepository {

    void insert(AbstractMessage message);

    void insert(AbstractMessage message, AbstractGroup group);
}

这样的设计是否可行?或者每个实体都应该有自己的包?我在过度思考吗?

com
 +- example
     +- myapplication
         +- Application.java
         |
         +- message
         |   +- AbstractMessage.java
         |   +- IMessageRepository.java
         |   +- MessageRepositoryImpl.java
             |  +- messageTypeA
             |     +- messageTypeA.java
             |     +- messageTypeAService.java
             |  +- messageTypeB
             |     +- messageTypeB.java
             |     +- messageTypeBService.java
             |
             +- group
                +- AbstractGroup.java
                +- GroupTypeX.java // same service as message, just different entity
                +- GroupTypeY.java // same service as message, just different entity
2个回答

6

这更多是基于观点的事情,但我想给你一些建议。

首先是命名。接口上的I前缀是IBM的一种“古老”技术,用于识别它们。请不要这样做,它是多余的,在新环境中没有意义。什么是I-MessageRepository?!
您会在Eclipse RCP项目或任何IBM产品中发现这种命名约定。

然后是实现名称。不要使用Impl后缀,它对正在阅读或编辑代码的人没有任何意义。
给它一个能表达其目的或领域范围的名称。

ActiveMQMessageRepository
FileMessageRepository
TcpMessageRepository

其次,代码仓库。 每个代码仓库应该只管理一种类型的对象,不要管理多个。使用服务(Services)来协调多个代码仓库。这将使得调试更加容易,并且它将解耦很多代码。


第三,包(Packages)。 尽量保持扁平化的包结构。扁平的结构更易于维护、查看和理解。不要创建数十个子包,例如

- messages
   - services
       MessageService
     - implementations
        ...
   - repositories
       MessageRepository
     - abstract
         AbstractMessageRepository
     - implementations
         TextMessageRepository
   - exceptions
     - runtime
     - checked
         UnsupportedMessageException

糟糕且无用。而且您无法利用包可见性

因此,将messagesgroups保持在不同的包中,并为它们提供自己的Repository

从软件包中公开接口,而不是具体实现。(如果可能的话)


那些名字本来就是虚构的,我只是在这里指定了这些值,以便人们更容易意识到它是一个接口! - Tiberiu
虽然我不理解的是,你说要公开接口,但是repositories只应该管理单个对象类型?你所说的单个对象类型是指接口,而不是具体实现,对吗?例如,我的存储库正在管理我的“消息”接口,然后再创建第二个存储库来管理我的“组”接口。而不是为每个具体实现都创建一个repository - Tiberiu
2
@Tiberiu 当然,我是指只接受一种类型的接口。这样做可以更容易地使您的存储库和服务尽可能小。代码越少,错误越少;) - LppEdd
@LppEdd 在一个将被继承的类中使用BaseEntity或AbstractEntity这样的名称是一个好的编程实践吗? - Braian Silva
1
@BraianSilva 嗯,这真的取决于情况。如果你的代码库中每个基类/抽象类都提供相同类型的基本功能,那么这种命名可能可行。否则,最好考虑另一个描述性名称。 - LppEdd

0

我同意上面@LppEdd的回答。只有一个问题,当你说

(我们之所以将它们保存为不同的实体,仅仅是因为这样更容易推导分析)。


他们可能正在测量那些域模型的工作量。 - LppEdd
好的,如果是这种情况,他们可以使用Hibernate Envers进行审计。如果将来有需要将代码拆分为微服务,您可以将服务拆分为单独的模块,但如果不是这种情况,我支持LppEdd的上述回答。 - bornleo
@bornleo 我的意思是我们收到的消息(以原样存储在表中)是它们自己的“实体”。在这个消息中,有一个可以拥有多个值的字段“group”(类似于map或2d数组)。与其在数据库中使用“2darray”数据类型,我们更喜欢创建一个单独的表并通过唯一键链接它们。因此,我创建了第二个实体“group”,因为它现在有了自己的表格(即使在原始的“message”中它实际上是一个字段--因此引发了包层次结构问题)。 - Tiberiu
群组实体是否可以独立于消息进行查询?如果是,那么一定需要一个单独的存储库;否则,您可以拥有单独的表,但仍然只需一个存储库。明白吗? - bornleo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接