我是否应该使用用例,即使它仅充当接口适配器的中间人?
Should I use a Use Case even though it only acts as a middle-man to the Interface Adapter?
我在我的项目中使用了 Clean Architecture。例如,现在我有一个像这样的接口适配器:
protocol UserRepositoryInterface {
func getSingle(id: String) -> Single<User?>
func getAll() -> Single<[User]>
}
class UserRepositoryAdapter: UserRepositoryInterface {
private let api: ApiService
private let mapper: UserMapper
init(api: ApiService,
mapper: UserMapper) {
self.api = api
self.mapper = mapper
}
func getSingle(id: String) -> Single<User?> {
return getAll()
.map { [=10=].first(where: { [=10=].id == id }) }
}
func getAll() -> Single<[User]> {
return api
.getUserList()
.compactMap { [weak self] in self?.mapper.map(from: [=10=]) }
}
}
还有一个像这样的简单用例:
protocol GetAllUsers {
func get() -> Single<[User]>
}
class GetAllUsersUseCase {
private let userRepo: UserRepositoryInterface
init(userRepo: UserRepositoryInterface) {
self.userRepo = userRepo
}
func get() -> Single<[User]> {
return userRepo.getAll()
}
}
代码在Swift,但可以是C#、C++、Java、Kotlin等任何其他语言。问题还是一样。从代码来看,GetAllUsersUseCase
只是充当InterfaceAdapter
和ViewModel
之间的中间人。我是否应该使用它,因为它什么都不做,应该被认为是一种气味? ViewModel
不应该直接使用 UserRepositoryInterface
吗?但是,我在 https://refactoring.guru/smells/middle-man:
上读到了这篇文章
When to Ignore
Don’t delete middle man that have been created for a reason:
A middle man may have been added to avoid interclass dependencies.
Some design patterns create middle man on purpose (such as Proxy or
Decorator).
这只是我们可以容忍上面提到的代码味道的例子之一吗(因此我仍然应该使用用例)?
谢谢。
CA 中“输入端口”概念实现的用例。从视图模型直接跳转到域存储库界面就好像您声明要按原样将用户请求传递到存储库,因此在存储库内应用业务验证。
当然,此类验证不应发生在基础设施层。相反,它们应该出现在领域实体内部,这些领域实体应该在应用层内部进行管理(而不是在表示层内部);或在管理上述域实体的那些确切对象中,即应用程序服务或用例。
坚持用例对象的另一个原因是您可能需要丰富获取所有用户的流程。虽然目前的需求可能很简单,但在未来的某个时候可能有必要,例如,根据某些标准过滤掉一些用户。当您有一个用例对象时,可以最好地满足这种缩放,例如,您可以在其中添加 SelectedUsers
规范并将其传递给存储库方法。规范不存在于视图模型中,而是存在于应用层中。
我在我的项目中使用了 Clean Architecture。例如,现在我有一个像这样的接口适配器:
protocol UserRepositoryInterface {
func getSingle(id: String) -> Single<User?>
func getAll() -> Single<[User]>
}
class UserRepositoryAdapter: UserRepositoryInterface {
private let api: ApiService
private let mapper: UserMapper
init(api: ApiService,
mapper: UserMapper) {
self.api = api
self.mapper = mapper
}
func getSingle(id: String) -> Single<User?> {
return getAll()
.map { [=10=].first(where: { [=10=].id == id }) }
}
func getAll() -> Single<[User]> {
return api
.getUserList()
.compactMap { [weak self] in self?.mapper.map(from: [=10=]) }
}
}
还有一个像这样的简单用例:
protocol GetAllUsers {
func get() -> Single<[User]>
}
class GetAllUsersUseCase {
private let userRepo: UserRepositoryInterface
init(userRepo: UserRepositoryInterface) {
self.userRepo = userRepo
}
func get() -> Single<[User]> {
return userRepo.getAll()
}
}
代码在Swift,但可以是C#、C++、Java、Kotlin等任何其他语言。问题还是一样。从代码来看,GetAllUsersUseCase
只是充当InterfaceAdapter
和ViewModel
之间的中间人。我是否应该使用它,因为它什么都不做,应该被认为是一种气味? ViewModel
不应该直接使用 UserRepositoryInterface
吗?但是,我在 https://refactoring.guru/smells/middle-man:
When to Ignore
Don’t delete middle man that have been created for a reason:
A middle man may have been added to avoid interclass dependencies.
Some design patterns create middle man on purpose (such as Proxy or Decorator).
这只是我们可以容忍上面提到的代码味道的例子之一吗(因此我仍然应该使用用例)?
谢谢。
CA 中“输入端口”概念实现的用例。从视图模型直接跳转到域存储库界面就好像您声明要按原样将用户请求传递到存储库,因此在存储库内应用业务验证。
当然,此类验证不应发生在基础设施层。相反,它们应该出现在领域实体内部,这些领域实体应该在应用层内部进行管理(而不是在表示层内部);或在管理上述域实体的那些确切对象中,即应用程序服务或用例。
坚持用例对象的另一个原因是您可能需要丰富获取所有用户的流程。虽然目前的需求可能很简单,但在未来的某个时候可能有必要,例如,根据某些标准过滤掉一些用户。当您有一个用例对象时,可以最好地满足这种缩放,例如,您可以在其中添加 SelectedUsers
规范并将其传递给存储库方法。规范不存在于视图模型中,而是存在于应用层中。