Sal*_*anz 2 architecture software-design clean-architecture
我正在尝试使用 Kotlin 实现干净的架构。该过程的流程将是:
usecase --> get rowresult from DB --> map rowresult to entity --> entity used by the usecase to check business rules
代码示例:
UserTable
------------------
id (varchar)
email (varchar)
password (varchar)
gender (varchar)
phone (varchar)
anotherAttribute1
anotherAttribute2
.
anotherAttributeN
Run Code Online (Sandbox Code Playgroud)
class UserEntity {
val id: String,
val email: String,
val password: String,
//Business rules
fun isUserAllowedToLogin(): Boolean {
//validate password
}
}
interface UserDataStore {
fun getUser(email: String): User
}
class UserDataStoreImplementation {
fun getUser(email: String): User {
//query to DB
val resultRow = db.query("SELECT id, email, password from UserTable where email=${email}")
//map to UserEntity
val user: UserEntity = Mapper.toUserEntity(userResultRow)
return user
}
}
class LoginUseCase {
fun execute(emailInput: String, passwordInput: String): Boolean {
val user = UserDataStore().getUser(emailInput)
if (!user.isUserAllowedToLogin) {
//do something
}
return result
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,loginUseCase 使用的唯一属性是用户电子邮件和密码。
问题 1. 假设如果我有另一个用例(GetUserFullDetailAndStaffDetail 用例)将使用更复杂的 User 属性,我是否应该为 GetUserFullDetailAndStaffDetail 用例使用相同的 UserEntity?所以 UserEntity 将是:
class UserEntity {
val id: String,
val email: String,
val password: String,
val gender: String,
val phone: String,
//more attributes
.
.
//more complex object
val Staff: Staff
fun isUserAllowedToLogin(): Boolean {
//validate password
}
fun checkStaffStatus(): Boolean {
//do something
}
}
class UserDataStoreImplementation {
fun getUser(email: String): User {
//query from DB which will have a lot of attributes
val resultRow = db.query("SELECT * from UserTable where email=${email}")
//map to UserEntity
val user: UserEntity = Mapper.toUserEntity(userResultRow)
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用不同的实体,它将违反 DRY 原则(在 UserDataStoreImplementation 中重复 UserEntity 和重复的 getUser 方法),但如果我对 GetUserFullDetailAndStaffDetail 用例使用相同的 UserEntity,则 LoginUseCase 的 UserDataStoreImplementation 中的 getUser 必须获取无用的完整属性。
问题 2. UserDataStoreImplementation 中的 getUser 是否应该有不同的方法(一种将在 LoginUseCase 中返回 UserTable 中的部分属性,另一种将在 GetUserFullDetailAndStaffDetail UseCase 中返回 UserTable 中的完整属性)?
问题 1. 假设如果我有另一个用例(GetUserFullDetailAndStaffDetail 用例)将使用更复杂的 User 属性,我是否应该为 GetUserFullDetailAndStaffDetail 用例使用相同的 UserEntity?
该实体是一个域对象,并且 aLoginUser与 a 不同UserDetail。我们常常认为有一个User。但用户有不同的观点。您可以将它们视为一种角色。
public class LoginUser {
private String name;
private String email;
// ...
}
Run Code Online (Sandbox Code Playgroud)
或一个DetailUser.
public class DetailUser {
private String name;
private String email;
private String phone;
private String gender;
// ...
}
Run Code Online (Sandbox Code Playgroud)
id正如你所看到的,我省略了。通常它是数据库详细信息而不是域属性。但有时它是,例如客户编号。
如果我使用不同的实体,它将违反 DRY 原则(在 UserDataStoreImplementation 中重复 UserEntity 和重复的 getUser 方法),但如果我对 GetUserFullDetailAndStaffDetail 用例使用相同的 UserEntity,则 LoginUseCase 的 UserDataStoreImplementation 中的 getUser 必须获取无用的完整属性。
它并不违反干燥原则,因为你不会重复自己。我同意我们必须删除重复的代码,但是 aLoginUser会因为不同的原因而改变,然后 a DetailUser。因此它们不会重复。这就是单一责任的含义。
它们看起来很相似,但相似只是重复的暗示。你必须问自己更多的问题,看看它们是否真的重复。让我们考虑一下登录用例的更改。也许只应该显示名称。那么这两个实体将只有 1 个共同属性 - 名称。它们必须有多少共同属性才能被复制?
如果您在实体中实现业务逻辑,您将意识到有些方法只会在两个用例之一中调用,并且这些方法仅使用属性的子集。然后你会发现这两个实体是不同的。
问题 2. UserDataStoreImplementation 中的 getUser 是否应该有不同的方法(一种将在 LoginUseCase 中返回 UserTable 中的部分属性,另一种将在 GetUserFullDetailAndStaffDetail UseCase 中返回 UserTable 中的完整属性)?
我想说每个用例都应该定义它自己的存储库接口。该接口应该只定义该用例所需的方法。这是接口隔离原则的应用,并且遵循单一责任原则。
就像您指出的那样,一个方法将返回完整的属性,因为它服务于 GetUserFullDetailAndStaffDetail 用例。
如果您只为所有用例使用一个存储库接口,您很快就会意识到它会不断增长,直到包含数十种方法。最终这个界面会变得混乱。有些方法相似,但又不同,你会尝试找到疯狂的名称来区分它们。
public interface UserRepository {
public User findSimpleUser();
public User findAllUserInfo();
public User findAllUserInfoForOrderProcess();
// ... maybe dozens more
}
Run Code Online (Sandbox Code Playgroud)
实现类会很大。也许许多方法是通过私有实用程序方法耦合的,因此对此共享代码的更改会影响其他用例,等等。
分离接口是个好主意。也许您从不同的接口开始,但只有一个实现同时实现了这两种接口。也许当情况变得更糟时,您想稍后分解实施。但是这样您就已经拥有了独立的接口,并且不必更改您的用例。
| 归档时间: |
|
| 查看次数: |
1128 次 |
| 最近记录: |