【问题标题】:DDD: what methods should entity contain?DDD:实体应该包含哪些方法?
【发布时间】:2020-01-08 14:47:32
【问题描述】:

我有代表用户授权的类(scala 代码):

case class Authorization(
                     userId: UUID,
                     permissions: Seq[String],                     
                     userRoles: Seq[String],
                     companyId: UUID
                   ) {

  private val policy = new Policy(permissions)

  def isAllowed(path: String, action: String): Boolean = policy.isAllowed(path, action)

  def isSuperuser: Boolean = userRoles.contains(SuperUser)

} 

该类在应用程序中的很多地方都使用,以检查用户是否对特定实体具有特定权限,例如:

authorization.isAllowed(s"some/entity/path/$id", "read")

为了提高可用性并避免直接的字符串操作,我将这些方法封装在更具体的方法中:

def canViewCompany(companyId:UUID)=authorization.isAllowed(s"company/$companyId","read")

def canViewUser(userId:UUID)=authorization.isAllowed(s"user/$userId","read")

def canEditTask(id:UUID)=authorization.isAllowed(....)

....

等等,最多 20 种方法。 Authorization 是否应该包含 canViewCompany() 之类的方法?
此类是否有责任了解每个特定实体检查?

更新: 所以最终的问题是:

  1. 创建像这样的包装器是个好主意吗 canViewCompany(companyId:UUID)为了提高可用性 上课?
  2. 如果是这样,这些方法应该被替换在Authorization 本身还是 提取到某些服务,例如:PermissionService.canViewCompany(id,authorization)=authorization.isAllowed()?

【问题讨论】:

  • path不是域外的吗?这些权限是否与域或 API 相关?域应该验证这些还是它们应该是应用层的一部分(例如,在应用服务中)?

标签: entity domain-driven-design domainservices ddd-service


【解决方案1】:

我的方法是加载具有所有权限的 UserPrincipal(解释 .net),并有一个方法可以检查某些权限是否在 Seq[Permissions] 中。 Permission 可以是具有pathaction 的对象。使用这种方法,您不需要创建一大堆方法。只有一种方法可以验证路径和操作。此外,它还允许您在应用程序中传递此对象,而无需担心在每个操作中检查数据库。

简而言之,您应该有一个负责身份验证/授权的服务。此服务创建一个 UserPrincipal ,其中包含您检查访问权限所需的所有数据。

有意义吗?

【讨论】:

  • 但似乎我已经有了这样一个 - 它是 isAllowed(path: String, action: String) 方法检查某些权限是否在权限集中,但将此逻辑委托给内部 Policy 类。
【解决方案2】:

在 DDD 中,只有与实体相关的方法才应该位于实体类中,例如 createupdate。这种方法只适用于实体属性和字段。据我所知,Authorization 是服务而非实体,因此最好将其定义为服务,以便在其中使用UserPolicy 等其他实体来执行isAllowed 等操作. 最后,您应该将与Authorization 相关的方法合并到此服务中。

【讨论】:

  • AFAIN实体可以包含任何业务逻辑,但是如果某些逻辑被多个实体重叠或者只是超出实体范围,则应该进入域服务。乍一看还不清楚Authorization 到底应该是什么。
【解决方案3】:

这里的授权似乎不是一个实体——它是用户的一个属性。它的键是 UserID 的事实可以暗示这一点。

更清晰的是像

user.IsAllowed(action, path)

user.canView(company)

如何实现取决于实体 - 你可能有授权服务等。

【讨论】:

    【解决方案4】:

    您提到的Authorization 服务似乎就像一个工具箱,其领域含义实际上很差。您正在尝试使用某种对象,创建某种抽象,将某种行为封装在“通用”服务中。

    正如您所说,只要您的域中有新的需求,这个对象就会增长。所以基本上你不得不一直修改你的代码,打破SOLID的open-closed principle

    我建议您将授权给定用户执行给定操作的责任转移到内部用例中,这样您的域中就会有多个永远不会改变的用例,每个用例他们知道自己的授权逻辑。

    修改这些用例的唯一原因是该特定用例的授权逻辑是否发生变化,但这没关系,因为如果逻辑发生变化,您的域也会发生变化。

    将这一职责转移到用例中将有助于您创建更具可扩展性和可扩展性的代码。

    当然,视情况而定,但经验法则是尽可能多地将逻辑推送到您的域中,这并不意味着创建大量域服务来存储该逻辑,因为这样您将创建一个anemic domain model,而你不希望这样。

    此外,我建议您应用TELL DON'T ASK 原则以保持逻辑简单。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 2019-03-17
      • 2023-02-23
      • 1970-01-01
      • 2010-10-11
      • 2016-02-15
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多