DDD中业务模型与框架等技术平台解耦的简单方法 - matthiasnoback


如果要编写可长期维护的应用程序,则必须与框架,ORM,HTTP客户端等分离,因为技术在发展,您的业务应用无法永远一直使用它们。
 
三个简单的规则
要完成框架解耦,您只需遵循以下简单规则:

  1. 所有服务都应获取其所有依赖项和配置值作为构造函数参数注入。当依赖项使用IO时,您必须为其引入一个抽象。
  2. 其他类型的对象不应该承担服务责任。
  3. 上下文信息应始终作为方法参数传递。

详细说明
  • 规则1

遵循规则1可确保服务所有依赖项是通过构造函数注入的,这样您久不会通过诸如使用方法参数Container::get(UserRepository::class)来引入依赖。这条规则对于框架解耦是必需的,因为根据定义,为您返回服务的全局静态工具是特定于框架的。获取配置值(例如Config::get('email.default_sender'))也是如此。
有时,依赖项使用IO,即与数据库,文件系统等进行通信。在这种情况下,您应该为依赖项引入一个抽象(如为防止与数据库依赖引入Repository模式:比较DAO与Repository存储库模式)。如果您依赖于具体的类,则该类将仅与当前正在使用的特定库或框架一起使用,因此,为了保持脱钩状态,您应该使用自己的抽象,并结合使用当前库的实现/框架。
  • 规则2

除了服务之外,还有其他几种类型的对象,例如实体,值对象,域事件和数据传输对象,所有这些对象都不承担服务责任。它们都不应该承担服务责任,因为这意味着它们将通过某些全局静态工具调用服务,或者它们需要特殊的框架/特定于ORM的设置,这意味着它们不能孤立使用,也无法在主要框架升级中生存下来或切换。不遵循规则2的对象的一个​​示例是活动记录模型(active record),它看起来像一个实体,但是能够保存自身,这实际上是一种服务责任。
  • 规则3

上下文信息通常来自当前的Web请求或用户会话,例如当前登录的用户的ID。与其在需要时获取数据(如Auth::getUser()->getId()),应该在在常规方法之间将其作为方法参数传递。
 
规则1、2和3结合在一起,可以确保对于每种方法,它都完全清楚自己在做什么,需要什么数据以及依靠什么服务依赖项来工作。最重要的是,所有依赖项或方法参数都不是框架或库特定的,这意味着您的应用程序代码将有效地与框架分离。