Tha*_*man 8 android kotlin clean-architecture
我和我的同事正在争论哪里才是将实体对象或远程 dto 对象映射到简单域对象的正确位置。
我们的结构看起来像这样。
源(包括 dao)> 存储库(包括源)> 用例(包括存储库)
我的同事认为映射到域应该在源内部完成,以便域对象可以传递到下一层,如下所示
class SomeSourceImpl(private val dao: Dao) : SomeSource {
override fun get(): Observable<DomainModel> {
return dao.getResponse().map { it.mapToDomain() }
}
}
Run Code Online (Sandbox Code Playgroud)
我的同事认为,根据鲍勃叔叔的说法,这是由于依赖规则造成的。
该规则规定源代码依赖关系只能指向内部。内圈中的任何事物都无法了解外圈中的任何事物。特别是,在内圈中的代码中不得提及外圈中声明的内容的名称。这包括函数、类。变量,或任何其他命名的软件实体。
我非常不同意直接映射到源内部域的方法,因为这样存储库就会变得贫乏,我们因此采用贫乏存储库无用的反模式,它们所做的就是盲目传播来自源的所有内容。(现在你可能会说源也很贫乏,我们可以简单地删除它们并将 dao 对象直接包含到存储库中,但这在我们的例子中是不可能的)。
相反,我建议源返回原始数据库实体(如果我们进行休息调用,则返回远程实体),因为源返回原始数据以供以后处理是有意义的。存储库的工作是从源获取结果,然后将其映射到域,最后将此域对象传播到类似这样的用例。
class SomeRepoImpl(private val someSource: SomeSource) : SomeRepo {
override fun get(haId: String): Observable<DomainModel> {
return otherAssetSource.get().map { it.mapToDomain() }
}
Run Code Online (Sandbox Code Playgroud)
我还在 github 上发现了一些示例,它们映射到存储库内的域而不是源
这也是 iOS 版的
关于可以将实体映射到域对象的位置,干净架构原则中的严格规则是什么?
引用规则
源代码依赖只能指向内部
我想这取决于架构。让我用一个例子来解释这一点:
建筑学:
DOMAIN <- DATA <- PRESENTATION
Run Code Online (Sandbox Code Playgroud)
在哪里:
DATA -> LOCAL
|
v
REMOTE
Run Code Online (Sandbox Code Playgroud)
注意: DOMAIN 代表最内圈,PRESENTATION 代表最外圈。
现在 DOMAIN 是一个纯 Kotlin 模块,没有任何 Android 依赖项。让我们定义一个存储库:
DOMAIN <- DATA <- PRESENTATION
Run Code Online (Sandbox Code Playgroud)
我们在数据层(这是一个 Android 库)中实现它:
class ProfileRepositoryImpl(
private val networkManager: NetworkManager,
private val remoteDataSource: ProfileRemoteDataSource,
private val localDataSource: ProfileLocalDataSource
): ProfileRepository {
override fun getProfile(): Profile? {
return if(networkManager.isNetworkAvailable) {
localDataSource.insert(remoteDataSource.get())
} else {
localDataSource.get()
}
}
override fun updateProfile(profile: Profile): Profile {
val updatedProfile = remoteDataSource.update(profile)
return localDataSource.insert(updatedProfile)
}
}
Run Code Online (Sandbox Code Playgroud)
DATA -> LOCAL
|
v
REMOTE
Run Code Online (Sandbox Code Playgroud)
interface ProfileRepository {
fun getProfile(): Profile?
fun updateProfile(profile: Profile): Profile
}
Run Code Online (Sandbox Code Playgroud)
class ProfileRepositoryImpl(
private val networkManager: NetworkManager,
private val remoteDataSource: ProfileRemoteDataSource,
private val localDataSource: ProfileLocalDataSource
): ProfileRepository {
override fun getProfile(): Profile? {
return if(networkManager.isNetworkAvailable) {
localDataSource.insert(remoteDataSource.get())
} else {
localDataSource.get()
}
}
override fun updateProfile(profile: Profile): Profile {
val updatedProfile = remoteDataSource.update(profile)
return localDataSource.insert(updatedProfile)
}
}
Run Code Online (Sandbox Code Playgroud)
该LOCAL模块是一个独立于任何依赖项的 Android 库,并公开DAO和Entity对象:
interface ProfileDao {
fun insert(profile: ProfileEntity)
fun get(): ProfileEntity?
}
Run Code Online (Sandbox Code Playgroud)
同样,对于REMOTE模块:
interface ProfileApi {
fun get(): ProfileDto
fun update(profile: ProfileDto): ProfileDto
}
Run Code Online (Sandbox Code Playgroud)
Source因此,让类返回DTO和Entity对象对我来说没有意义。回购类看起来像这样:
class ProfileRepositoryImpl(
private val networkManager: NetworkManager,
private val remoteDataSource: ProfileRemoteDataSource,
private val remoteDataMapper: Mapper<ProfileDto, Profile>,
private val localDataSource: ProfileLocalDataSource,
private val localDataMapper: Mapper<ProfileEntity, Profile>
) : ProfileRepository {
override fun getProfile(): Profile? {
if (networkManager.isNetworkAvailable) {
val dto = remoteDataSource.get()
val profile = remoteDataMapper.toModel(dto)
val entity = localDataMapper.fromModel(profile)
localDataSource.insert(entity)
}
return localDataSource.get()?.let(localDataMapper::toModel)
}
override fun updateProfile(profile: Profile): Profile {
val request = remoteDataMapper.fromModel(profile)
val dto = remoteDataSource.update(request)
val updatedProfile = remoteDataMapper.toModel(dto)
val entity = localDataMapper.fromModel(updatedProfile)
localDataSource.insert(entity)
return localDataMapper.toModel(
requireNotNull(localDataSource.get())
)
}
}
Run Code Online (Sandbox Code Playgroud)
在您的示例中,您仅GET考虑了操作。在这里,对于操作我们还UPDATE需要映射对象。DOMAIN因此,当我们添加更多功能时,如果对象的映射是在 Repo 类中完成的,那么 Repo 类会变得非常混乱。
我相信这将取决于系统的整体架构。
| 归档时间: |
|
| 查看次数: |
4483 次 |
| 最近记录: |