在鲍勃叔叔架构中,加载非数据库实体时是否总是加载整个实体?
In uncle bob architecture, when loading a non DB entity do you always load the entirety of the entity?
上下文:
Bob 大叔有一个例子叫做工资单例子。这个页面有一个很好的可下载示例和演练,它到底是什么:http://cleancodejava.com/uncle-bob-payroll-case-study-full-implementation/#disqus_thread.
在工资单示例中,一名员工有 4 个 类 代表工资 schedule/pay type/etc..(理论上可能来自 20 个不同的表)。有各种“交互器”与这些 类 中的每一个进行交互。交互者使用网关通过 findById() 访问员工,return 是一个加载的员工,所有 4 类 也从数据库中检索。
问题:
这在示例中很好,但在更大的系统中,我 运行 遇到了一些关于实体获取的问题。
出现了一个新用例,我们只想编辑员工姓名。使用网关 findById returns 一个员工(太棒了!),但也会对 updateEmployeeName 交互器不必要的 4 个额外 类 进行一堆不必要的加载。
所以:
- 我们是否根据用例部分加载员工?这意味着网关可能有许多更高度专业化的加载方法。
- 我们是否加载了一种全新类型的精简员工? (NamableEmployee) 这意味着很多实体都只满足特定的用例。
- 实体是否根据需要“延迟加载”其他字段?这意味着该实体将需要一个网关来访问其在其他表中的子字段。
- 关于这可能如何运作的任何其他想法?
还是我完全误解了实体的意思?这就是为什么在这个架构中员工是抽象的原因吗?所以网关可以 return 精简仍然“显示”为员工的版本?
非常感谢!
Using the gateway findById returns an employee (great!) but also does a bunch of unnecessary loading of the 4 extra classes that are unnecessary
您似乎将数据库实体与实体混合在一起。干净架构中的实体不是数据库实体。您不应在这些实体中包含任何数据库详细信息。这甚至包括某些框架使用的注释,例如@Entity(table="employee")
将业务实体与数据库实体分开。如果这样做,您可以将实体与它们的持久化方式分离。在某些情况下,您可能会使用纯 sql,而在其他情况下,您可能会使用 ORM 框架。但是如果你解耦它们,你可以根据持久化需求设计数据库实体,根据业务需求设计业务实体。这也是单一职责原则的应用,因为两者因不同原因而变化。
Do we partially load the employee based on the use case? This means the gateway may have many many more highly specialized loading methods.
是的,你知道。但是您也可以为该类型的用法引入一个实体。例如。仅具有可更新属性的 EmployeeUpdate
。
Does the entity "lazy load" other fields as necessary? This means the entity would need a gateway to access its sub fields that are in other tables.
实体永远不应加载任何字段。如果是,则它不是业务实体,而是某种 ORM 框架提供的数据库实体。你应该按照我上面的解释将它们分开。
Any other ideas on how this may work?
当我们加载一个完整的实体来更新单个 属性 时,我们通常会考虑效率和性能。但我们也应该考虑用例本身。它是执行了很多次还是只执行了几次的用例。提供性能优化的重命名方法的努力是否值得,还是我们应该只加载整个数据?
最后,我将创建一个 returns 和 EmployeeUpdate
的存储库。例如
public interface UpdateEmployeeRepository {
public EmployeeUpdate getEmployeeForUpdate(int employeeNumber);
public void applyEmployeeUpdate(EmployeeUpdate eu);
}
如您所见,我还将指定一个特定于用例的存储库接口。这也是单一职责原则的应用。
也许 Uncle Bob 的 this talk 也能帮到你。
编辑
I was wondering if there were entities for specific use cases and it sounds like so! Definitely seems like there could be a lot entity bloat (e.g. 50 different entities that can all update different features etc)
您可以将其视为同一实体的不同接口或实体在不同用例中扮演的不同角色。
对我来说,界面就像是对一件事的透视。如果我手里拿着什么东西,我可以把它转过来,从每个角度看它都会不同(除非它是一个球体)。这同样适用于接口。在您的用例中,您从更新角度查看 Employee
实体。
Vaughn Vernon 的 Implementing domain-driven-design 一书的第 5 章实体 也可能对您有所帮助。在第 200 页上,他从 角色和职责 部分开始,描述了 域对象如何扮演多个角色 并且还讨论了陷阱。例如。他谈到 object schizophrenia。我以前知道的一个概念,但是我第一次在他的书中读到的术语。本书包含 Java 和 C# 中的代码示例。一本非常棒的书,因为它消除了 Eric Evans 书 Domain Driven Design 和实现问题之间的差距。
上下文:
Bob 大叔有一个例子叫做工资单例子。这个页面有一个很好的可下载示例和演练,它到底是什么:http://cleancodejava.com/uncle-bob-payroll-case-study-full-implementation/#disqus_thread.
在工资单示例中,一名员工有 4 个 类 代表工资 schedule/pay type/etc..(理论上可能来自 20 个不同的表)。有各种“交互器”与这些 类 中的每一个进行交互。交互者使用网关通过 findById() 访问员工,return 是一个加载的员工,所有 4 类 也从数据库中检索。
问题:
这在示例中很好,但在更大的系统中,我 运行 遇到了一些关于实体获取的问题。
出现了一个新用例,我们只想编辑员工姓名。使用网关 findById returns 一个员工(太棒了!),但也会对 updateEmployeeName 交互器不必要的 4 个额外 类 进行一堆不必要的加载。
所以:
- 我们是否根据用例部分加载员工?这意味着网关可能有许多更高度专业化的加载方法。
- 我们是否加载了一种全新类型的精简员工? (NamableEmployee) 这意味着很多实体都只满足特定的用例。
- 实体是否根据需要“延迟加载”其他字段?这意味着该实体将需要一个网关来访问其在其他表中的子字段。
- 关于这可能如何运作的任何其他想法?
还是我完全误解了实体的意思?这就是为什么在这个架构中员工是抽象的原因吗?所以网关可以 return 精简仍然“显示”为员工的版本?
非常感谢!
Using the gateway findById returns an employee (great!) but also does a bunch of unnecessary loading of the 4 extra classes that are unnecessary
您似乎将数据库实体与实体混合在一起。干净架构中的实体不是数据库实体。您不应在这些实体中包含任何数据库详细信息。这甚至包括某些框架使用的注释,例如@Entity(table="employee")
将业务实体与数据库实体分开。如果这样做,您可以将实体与它们的持久化方式分离。在某些情况下,您可能会使用纯 sql,而在其他情况下,您可能会使用 ORM 框架。但是如果你解耦它们,你可以根据持久化需求设计数据库实体,根据业务需求设计业务实体。这也是单一职责原则的应用,因为两者因不同原因而变化。
Do we partially load the employee based on the use case? This means the gateway may have many many more highly specialized loading methods.
是的,你知道。但是您也可以为该类型的用法引入一个实体。例如。仅具有可更新属性的 EmployeeUpdate
。
Does the entity "lazy load" other fields as necessary? This means the entity would need a gateway to access its sub fields that are in other tables.
实体永远不应加载任何字段。如果是,则它不是业务实体,而是某种 ORM 框架提供的数据库实体。你应该按照我上面的解释将它们分开。
Any other ideas on how this may work?
当我们加载一个完整的实体来更新单个 属性 时,我们通常会考虑效率和性能。但我们也应该考虑用例本身。它是执行了很多次还是只执行了几次的用例。提供性能优化的重命名方法的努力是否值得,还是我们应该只加载整个数据?
最后,我将创建一个 returns 和 EmployeeUpdate
的存储库。例如
public interface UpdateEmployeeRepository {
public EmployeeUpdate getEmployeeForUpdate(int employeeNumber);
public void applyEmployeeUpdate(EmployeeUpdate eu);
}
如您所见,我还将指定一个特定于用例的存储库接口。这也是单一职责原则的应用。
也许 Uncle Bob 的 this talk 也能帮到你。
编辑
I was wondering if there were entities for specific use cases and it sounds like so! Definitely seems like there could be a lot entity bloat (e.g. 50 different entities that can all update different features etc)
您可以将其视为同一实体的不同接口或实体在不同用例中扮演的不同角色。
对我来说,界面就像是对一件事的透视。如果我手里拿着什么东西,我可以把它转过来,从每个角度看它都会不同(除非它是一个球体)。这同样适用于接口。在您的用例中,您从更新角度查看 Employee
实体。
Vaughn Vernon 的 Implementing domain-driven-design 一书的第 5 章实体 也可能对您有所帮助。在第 200 页上,他从 角色和职责 部分开始,描述了 域对象如何扮演多个角色 并且还讨论了陷阱。例如。他谈到 object schizophrenia。我以前知道的一个概念,但是我第一次在他的书中读到的术语。本书包含 Java 和 C# 中的代码示例。一本非常棒的书,因为它消除了 Eric Evans 书 Domain Driven Design 和实现问题之间的差距。