干净的架构:与不同的层共享相同的 models/entities
Clean architecture: share same models/entities with different layers
在我干净的架构 Android 应用程序设置中,我为每个层(数据、域、表示)都有自己的 Gradle 模块。我还为每一层都有自己的 models/entities,它们使用映射器从一层转换到另一层。这导致我有很多 kotlin 数据 classes 的情况,代表基本相同的东西,但在不同的层中。这听起来不对。
简单示例:
数据层 - Android库模块
@JsonClass(generateAdapter = true)
data class BuildingEntity(
@Json(name = "u_id")
val id: String,
val name: String,
val latitude: Double,
val longitude: Double,
@Json(name = "current_tenants")
val tenants: List<TenantEntity>? = null
)
领域层 - 纯 Kotlin 模块
data class Building(
val id: String,
val name: String,
val location: CoordinatePoint,
val tenants: List<Tenant>? = null
表示层 Android 应用程序模块
data class BuildingModel(
val id: String,
val name: String,
val location: LatLng,
val tenants: List<TenantModel> = listOf()
)
BuildingEntity
取自外网api.
这很好地将每个模块彼此分开,但在我的应用程序中,我有很多具有嵌套结构的不同实体。所以我最终写了很多 kotlin 数据 classes 和映射器。
如何简化这个?我可以删除 Building
class 并在数据和域层上使用 BuildingEntity
吗?只需在表示层将 BuildingEntity
转换为 BuildingModel
?
我正在尝试找到实际的答案,人们是如何解决这类问题的,而不是最终编写大量数据 classes 和映射器?
在我的域模块中,我将我的模型作为接口(Kotlin 允许我们在接口内有 vals),在数据模块中实现,而在演示中根本没有模型。
看看这个小样本:
域:
interface IUserModel {
val id: String
val name: String
}
interface UserRepository {
fun getUserDetails(id: String): IUserModel
}
数据:
@Entity
data class UserEntity(
@SerializedName("userId")
override val id: String,
override val name: String
) : IUserModel
class UserRepositoryImpl(val userDao: UserDao) : UserRepository {
override fun getUserDetails(id: String): IUserModel {
return userDao.getUser(id) //userDao.getUser returns a UserEntity
}
}
演示文稿:
class UserDetailsViewModel(val userId: String, val userRepository: UserRepository) : ViewModel() {
val userData: LiveData<IUserModel> = MutableLiveData()
fun getUserData() {
(userData as MutableLiveData).postValue(userRepository.getUserDetails(userId))
}
}
没有映射器,没有大量数据类。
我有几个具有这种结构的项目,有时需要一个映射器(将网络模型转换为数据库实体),但是使用接口作为域中的模型可以大大减少冗长。
我知道这是一个老问题,但我想贡献一点。
所以,是的,这是书本上的干净架构。如果您想 "break" 架构,那么我建议您放弃表示模型,而改用领域模型。
但是,在某些情况下,数据模型(实体)包含表示层不需要的信息。您需要在域和表示层中使用不同的模型。不要传递不需要的信息!
实际上,你这样做是对的。要使应用程序完全干净,您应该在每一层中对您的实体进行不同的表示,并使用映射器对其进行转换。这允许您仅在需要更改某些实体时更改映射器。
例如,您可能会从服务器收到一些您不想在 UI 中显示的数据,因此您不会在您的表示实体中包含这些数据。另一个例子是,如果您想更改数据实体中的参数名称。如果直接从演示文稿访问它,则需要更改所有访问权限。相反,如果您有映射器,您唯一要做的就是更改映射器。
显然,清洁架构是一个复杂的架构,它在大型和长期项目中更有意义,这些项目可能会更频繁地发生变化。所以,如果你想在做一个小应用程序时摆脱大量代码,那也没关系。在这种情况下,我会建议您对域和表示使用相同的实体,并为数据保留映射器,因为数据取决于 API,更改不取决于您,您会得到一些好处来自映射器。
在我干净的架构 Android 应用程序设置中,我为每个层(数据、域、表示)都有自己的 Gradle 模块。我还为每一层都有自己的 models/entities,它们使用映射器从一层转换到另一层。这导致我有很多 kotlin 数据 classes 的情况,代表基本相同的东西,但在不同的层中。这听起来不对。
简单示例:
数据层 - Android库模块
@JsonClass(generateAdapter = true)
data class BuildingEntity(
@Json(name = "u_id")
val id: String,
val name: String,
val latitude: Double,
val longitude: Double,
@Json(name = "current_tenants")
val tenants: List<TenantEntity>? = null
)
领域层 - 纯 Kotlin 模块
data class Building(
val id: String,
val name: String,
val location: CoordinatePoint,
val tenants: List<Tenant>? = null
表示层 Android 应用程序模块
data class BuildingModel(
val id: String,
val name: String,
val location: LatLng,
val tenants: List<TenantModel> = listOf()
)
BuildingEntity
取自外网api.
这很好地将每个模块彼此分开,但在我的应用程序中,我有很多具有嵌套结构的不同实体。所以我最终写了很多 kotlin 数据 classes 和映射器。
如何简化这个?我可以删除 Building
class 并在数据和域层上使用 BuildingEntity
吗?只需在表示层将 BuildingEntity
转换为 BuildingModel
?
我正在尝试找到实际的答案,人们是如何解决这类问题的,而不是最终编写大量数据 classes 和映射器?
在我的域模块中,我将我的模型作为接口(Kotlin 允许我们在接口内有 vals),在数据模块中实现,而在演示中根本没有模型。
看看这个小样本:
域:
interface IUserModel {
val id: String
val name: String
}
interface UserRepository {
fun getUserDetails(id: String): IUserModel
}
数据:
@Entity
data class UserEntity(
@SerializedName("userId")
override val id: String,
override val name: String
) : IUserModel
class UserRepositoryImpl(val userDao: UserDao) : UserRepository {
override fun getUserDetails(id: String): IUserModel {
return userDao.getUser(id) //userDao.getUser returns a UserEntity
}
}
演示文稿:
class UserDetailsViewModel(val userId: String, val userRepository: UserRepository) : ViewModel() {
val userData: LiveData<IUserModel> = MutableLiveData()
fun getUserData() {
(userData as MutableLiveData).postValue(userRepository.getUserDetails(userId))
}
}
没有映射器,没有大量数据类。
我有几个具有这种结构的项目,有时需要一个映射器(将网络模型转换为数据库实体),但是使用接口作为域中的模型可以大大减少冗长。
我知道这是一个老问题,但我想贡献一点。
所以,是的,这是书本上的干净架构。如果您想 "break" 架构,那么我建议您放弃表示模型,而改用领域模型。
但是,在某些情况下,数据模型(实体)包含表示层不需要的信息。您需要在域和表示层中使用不同的模型。不要传递不需要的信息!
实际上,你这样做是对的。要使应用程序完全干净,您应该在每一层中对您的实体进行不同的表示,并使用映射器对其进行转换。这允许您仅在需要更改某些实体时更改映射器。
例如,您可能会从服务器收到一些您不想在 UI 中显示的数据,因此您不会在您的表示实体中包含这些数据。另一个例子是,如果您想更改数据实体中的参数名称。如果直接从演示文稿访问它,则需要更改所有访问权限。相反,如果您有映射器,您唯一要做的就是更改映射器。
显然,清洁架构是一个复杂的架构,它在大型和长期项目中更有意义,这些项目可能会更频繁地发生变化。所以,如果你想在做一个小应用程序时摆脱大量代码,那也没关系。在这种情况下,我会建议您对域和表示使用相同的实体,并为数据保留映射器,因为数据取决于 API,更改不取决于您,您会得到一些好处来自映射器。