Answers:
我认为这绝对不是它的意思。这违反了DRY。
这个想法是对中间的实体/领域对象进行建模以尽可能好地表示领域。它是一切的中心,一切都可以依赖它,因为域本身在大多数情况下都不会改变。
如果外部的数据库可以直接存储这些对象,则将它们映射为另一种格式以分离层不仅是没有意义的,而且还创建了模型的副本,而这并非意图。
首先,构建干净的体系结构时要考虑到不同的典型环境/场景。具有庞然大物的外层的业务服务器应用程序需要自己类型的特殊对象。例如,产生SQLRow
对象并需要SQLTransactions
返回更新项目的数据库。如果要在中间使用它们,那么您将违反依赖关系指导,因为您的核心将依赖于数据库。
使用轻型ORM来加载和存储实体对象的情况并非如此。他们在内部SQLRow
域名和您的域之间进行映射。即使您需要将@Entitiy
ORM 的注释放入域对象中,我也会认为这不会建立外层的“提及”。因为注释只是元数据,所以没有专门寻找它们的代码不会看到它们。更重要的是,如果删除它们或将其替换为其他数据库的注释,则无需进行任何更改。
相反,如果您确实更改了域并创建了所有这些映射器,则必须进行很多更改。
修订:上面的内容有些简化,甚至可能是错误的。因为干净架构中有一部分希望您为每层创建一个表示。但这必须在应用程序的上下文中看到。
即在这里https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
重要的是,隔离的,简单的数据结构跨边界传递。我们不想欺骗并传递实体或数据库行。我们不希望数据结构具有违反“依赖关系规则”的任何依赖关系。
将实体从中心传递到外层不会违反依赖关系规则,但已提及它们。但这在设想的应用中具有一个原因。传递实体会将应用程序逻辑移到外部。外层将需要知道如何解释内部对象,它们将必须有效地完成内部层(如“用例”层)应该做的事情。
除此之外,它还使各层解耦,从而使更改核心不必更改外部层(请参见SteveCallender的评论)。在这种情况下,很容易看出对象应如何特别代表它们的用途。此外,各层还应根据专门为该通信目的制作的对象相互通信。这甚至可能意味着存在3种表示形式,每层1种,层间传输1种。
还有https://blog.8thlight.com/uncle-bob/2011/11/22/Clean-Architecture.html,该地址位于上面:
其他人担心我的建议的最终结果将是大量重复的代码,以及在系统各层之间从一个数据结构到另一个数据的很多死记硬背的复制。当然我也不想要这个。我所建议的一切都将不可避免地导致数据结构的重复和字段复制的过度。
IMO暗示对象的普通1:1复制在体系结构中是一种气味,因为您实际上并未使用适当的层和/或抽象。
后来他解释了他如何想象所有的“复制”
通过在两者之间传递简单的数据结构,可以将UI与业务规则分开。您不会让您的控制者对业务规则有所了解。相反,控制器将HttpRequest对象解压缩为简单的原始数据结构,然后将该数据结构传递给通过调用业务对象来实现用例的交互对象。然后,交互器将响应数据收集到另一个普通数据结构中,并将其传递回UI。视图不了解业务对象。他们只是查看该数据结构并提出响应。
在此应用程序中,表示形式之间存在很大差异。流动的数据不仅仅是实体。这保证并要求不同的等级。
但是,应用于像照片查看器这样的简单Android应用程序时,该Photo
实体具有大约0个业务规则,并且处理它们的“用例”几乎不存在,并且实际上更关心缓存和下载(该过程应由IMO更加清晰地表示),对照片进行单独表示的点开始消失。我什至感觉到照片本身是数据传输对象,而真正的业务逻辑核心层却缺失了。
“通过在两者之间传递简单的数据结构将UI与业务规则分开”与“当您要在途中将照片重命名3次时”之间存在区别。
除此之外,我看到这些演示应用程序无法代表干净的体系结构的地方在于,它们为了分离层而更加强调分离层,但有效地隐藏了应用程序的工作。这与https://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html中所说的相反-
软件应用程序的体系结构尖叫着关于应用程序的用例
我看不到在干净的体系结构中分离各层的重点。它是关于依赖关系的方向,并专注于代表应用程序的核心-实体和用例-在理想的纯Java中,不依赖外部。与该核心的依赖关系不大。
因此,如果您的应用程序实际上具有代表业务规则和用例的核心,并且/或者不同的人员在不同的层上工作,请以预期的方式将它们分开。另一方面,如果您只是自己编写一个简单的应用程序,请不要过度使用它。具有流畅边界的2层可能绰绰有余。以后也可以添加图层。
@SerializedName
Gson注释放在域模型上?还是您将创建一个负责将Web响应映射到域模型的新对象?
您实际上是正确的。而且,由于您接受SRP,因此不会违反DRY。
例如:您有一个业务方法createX(String name),那么您可能在DAO层中有一个方法createX(String name),在business-Method中被调用。它们可能具有相同的签名,也许只有一个代表团,但它们具有不同的目的。您还可以在UseCase上使用createX(String name)。即使那样,它也不是多余的。我的意思是:相同的签名并不意味着相同的语义。选择其他名称以使其语义清晰。命名本身完全不会影响SRP。
UseCase负责特定于应用程序的逻辑,业务对象负责与应用程序无关的逻辑,而DAO则负责存储。
由于语义不同,所有层都可能具有自己的表示和通信模型。通常,您将“实体”视为“业务对象”,而常常看不到将它们分开的必要性。但是,在“巨大”的项目中,应努力正确地分离各层。项目越大,就可能需要不同层和类中表示的不同语义。
您可以想到同一语义的不同方面。用户对象必须显示在屏幕上,它具有一些内部一致性规则,并且必须存储在某处。每个方面都应以不同的类(SRP)表示。创建映射器可能会很麻烦,因此在我从事这些方面工作的大多数项目中,我都融为一体。这显然违反了SRP,但是没有人真正在乎。
我称清洁架构和SOLID的应用“在社会上不可接受”。如果允许的话,我会处理的。目前,我不允许这样做。我等一下,我们必须考虑认真对待SOLID。
不,您不需要在每一层都创建模型类。
实体(DATA_LAYER
)-是数据库对象的完整或部分表示。DATA_LAYER
Mapper(DOMAIN_LAYER
)-实际上是一个将Entity转换为ModelClass的类,该类将用于DOMAIN_LAYER
BankAccount
规则,但是根据特定于应用程序的规则,您可以对该帐户执行哪些操作。