Android app clean 架构:数据层是否应该有自己的模型 类?
Android app clean architecture: Should data layer have its own model classes?
在开发 Android 应用程序并尝试遵循简洁的架构指南时,最好的方法是什么(但不是非常严格 - 因为对于较小的项目来说可能有点矫枉过正)。
就我而言,我不确定哪种方法最好(如果有的话)关于 数据层和如果数据层应该在自己的模型 classes 上运行,或者它是否可以直接在领域层模型上运行。
此外,如果数据层应该在自己的模型 classes 上运行,那么像 DB
或 API
这样的数据源是否应该有自己的模型(比如 API
使用 Retrofit
和 Gson
带有 Gson
注释的模型 class)然后映射到数据层模型 或 应该数据层模型本身是由 DB
和 API
编辑的模型 return(这意味着必须注释数据层模型,以便 Gson
能够在 Retrofit
和 Gson
)。
下面的图片应该阐明我的意思的 3 种方法:
在图 1 DB
和 API
return 具体型号 class 中。在 API
的情况下,它可能看起来像(使用 Retrofit
和 Gson
):
class ArticleResponse(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
然后这些由 Local/Remote 数据源映射到 Article
模型(由领域层使用)。因此,存储库在域层模型上运行并且正在打破边界,对吗?即方法 1。
在图 2 中,DB
和 API
仍然是 return 特定型号 class。在 API
的情况下,它可能看起来像(使用 Retrofit
和 Gson
):
class ArticleResponse(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
但是,这些模型随后会映射到数据层运行的数据层模型 (ArticleEntity
)。当响应领域层时,repository
将这些 ArticleEntity
映射到领域层模型 Article
。这不会打破边界(右),但它 需要在数据层中进行一些额外的映射 。这是方法 2。
在图 3 中,DB
和 API
已经 return 数据层模型 ArticleEntity
。因此,此模型 class 必须包含解析 API 请求(使用 Gson
)所需的所有注释:
class ArticleEntity(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
如果数据库还需要某种注释,那么这些注释也必须添加到 class(对吗?)。我能想到的这种方法的一个优点是模型 classes 更少(因为 DB 和 API 直接映射到数据层模型)。但是,这不会破坏数据层模型 class 和来自所有不同数据源(DB,API)的 annotations/properties 吗?是不是违反了从存储库中提取数据源的全部要点,因为数据层模型依赖于特定的数据源实现(例如,使用 Gson 来解析 API 具有准确 API 响应的请求名)。所以这是方法 3。
我的问题是:这 3 种方法中哪一种是最灵活和面向未来的方法?
如果我是你,我会选择 Image1 流程。我认为您的数据源的工作是获取来自您的数据库或 API 或您拥有的任何端点的任何对象,并将其转换为更易于在您的存储库中使用的对象。
在Image1和Image2之间,我认为这取决于你想要存储什么数据以及你想要存储的对象是什么。根据您的业务规则,您可能需要也可能不需要 ArticleEntity。如果您不需要它,则不必创建一个。
但对于某些用例,您可能需要创建该对象以将一些信息添加到您的文章中。例如,如果你想在其中放置一个有效日期或任何其他你只会在你的存储库中使用的信息,你可以选择 Image2。
在开发 Android 应用程序并尝试遵循简洁的架构指南时,最好的方法是什么(但不是非常严格 - 因为对于较小的项目来说可能有点矫枉过正)。
就我而言,我不确定哪种方法最好(如果有的话)关于 数据层和如果数据层应该在自己的模型 classes 上运行,或者它是否可以直接在领域层模型上运行。
此外,如果数据层应该在自己的模型 classes 上运行,那么像 DB
或 API
这样的数据源是否应该有自己的模型(比如 API
使用 Retrofit
和 Gson
带有 Gson
注释的模型 class)然后映射到数据层模型 或 应该数据层模型本身是由 DB
和 API
编辑的模型 return(这意味着必须注释数据层模型,以便 Gson
能够在 Retrofit
和 Gson
)。
下面的图片应该阐明我的意思的 3 种方法:
在图 1 DB
和 API
return 具体型号 class 中。在 API
的情况下,它可能看起来像(使用 Retrofit
和 Gson
):
class ArticleResponse(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
然后这些由 Local/Remote 数据源映射到 Article
模型(由领域层使用)。因此,存储库在域层模型上运行并且正在打破边界,对吗?即方法 1。
在图 2 中,DB
和 API
仍然是 return 特定型号 class。在 API
的情况下,它可能看起来像(使用 Retrofit
和 Gson
):
class ArticleResponse(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
但是,这些模型随后会映射到数据层运行的数据层模型 (ArticleEntity
)。当响应领域层时,repository
将这些 ArticleEntity
映射到领域层模型 Article
。这不会打破边界(右),但它 需要在数据层中进行一些额外的映射 。这是方法 2。
在图 3 中,DB
和 API
已经 return 数据层模型 ArticleEntity
。因此,此模型 class 必须包含解析 API 请求(使用 Gson
)所需的所有注释:
class ArticleEntity(@SerializedName("source") val source: SourceResponse,
@SerializedName("author") val author: String?,
@SerializedName("title") val title: String,
@SerializedName("description") val description: String?,
@SerializedName("url") val url: String,
@SerializedName("urlToImage") val urlToImage: String?,
@SerializedName("publishedAt") val publishedAt: String?)
如果数据库还需要某种注释,那么这些注释也必须添加到 class(对吗?)。我能想到的这种方法的一个优点是模型 classes 更少(因为 DB 和 API 直接映射到数据层模型)。但是,这不会破坏数据层模型 class 和来自所有不同数据源(DB,API)的 annotations/properties 吗?是不是违反了从存储库中提取数据源的全部要点,因为数据层模型依赖于特定的数据源实现(例如,使用 Gson 来解析 API 具有准确 API 响应的请求名)。所以这是方法 3。
我的问题是:这 3 种方法中哪一种是最灵活和面向未来的方法?
如果我是你,我会选择 Image1 流程。我认为您的数据源的工作是获取来自您的数据库或 API 或您拥有的任何端点的任何对象,并将其转换为更易于在您的存储库中使用的对象。
在Image1和Image2之间,我认为这取决于你想要存储什么数据以及你想要存储的对象是什么。根据您的业务规则,您可能需要也可能不需要 ArticleEntity。如果您不需要它,则不必创建一个。
但对于某些用例,您可能需要创建该对象以将一些信息添加到您的文章中。例如,如果你想在其中放置一个有效日期或任何其他你只会在你的存储库中使用的信息,你可以选择 Image2。