根据“Uncle Bobs”一书“Clean Architecture”,软件系统的核心由实体(关键业务规则)和用例(用例应该是一个对象)组成。用例建模与实体交互的流程,但用例应如何初始化实体对象?该书明确指出您不应将实体作为输入参数传递给用例类。另一方面:如果每个用例的输入必须包含与初始化实体相关的所有数据,并且实体在数百个用例中被重用,则实体参数的更改可能会变得痛苦。如果我需要实体中的另一个参数,我将不得不修改使用该实体的所有用例的输入。
解决这个问题的最佳方法是什么?
通常,实体是从注入用例的工厂或存储库中检索的。存储库或工厂负责进行初始化,从而将其与用例分离。
输入很少有初始化实体所需的所有数据,只是足以从 确实 拥有所有数据的东西请求该实体。例如,主键或查找值。
因此,例如,如果您有一个登录用例。您将在用例中接受用户名和密码。它 not 知道有关如何初始化存储在数据库(或 ldap、auth 服务等)中的用户的所有信息。它只知道用户的登录名和建议的密码。登录用例应该与用户存储库对话并通过该登录检索用户(不一定是主键,但仍然足够唯一以识别单个用户)。该存储库可以返回一个用户实体,您可以将密码与之进行比较。
以这种方式解耦意味着您可以轻松地更换您的存储库以拥有不同的商店,更重要的是,通过模拟它来轻松测试它。
用例建模一个与实体交互的流程,但是用例应该如何初始化实体对象?
用例通常通过其标识从存储库中检索实体对象,存储库初始化实体。
如果每个用例的输入必须包含与初始化实体相关的所有数据,并且实体在数百个用例中重复使用,则实体参数的更改可能会变得痛苦。
通常很少有创建主数据的用例,例如客户或产品。这些用例的性质是您将它们传递给它们初始化实体所需的所有必需属性。之后,他们使用存储库来保存他们创建的实体,以便其他用例稍后可以通过它们的 ID 检索它们。
如果你有很多需要所有实体数据的用例,你可能有另一个设计问题,或者你只是有很多创建用例。
您可能正在实现一个实际上没有用例的应用程序,因为它只是一个很好的数据库访问前端。在这些应用程序中,用例逻辑由用户完成。干净的架构不适合这些情况。