使用双分派解决领域实体和外部机制通讯问题

使用双分派解决领域实体和外部机制通讯问题

经典DDD分层中领域层领域实体自身高内聚,在领域层内经过聚合,实体,事件和仓储接口完成领域业务逻辑。
最近在实际项目中遇到一种场景,有以下所示实体Device:网络

public class Device
{
    void ExecuteCmd(string cmd)
    {
        //Do something "Domian" related before sending..
        //Send command to real device via network
    }
}

其中ExecuteCmd方法须要首先将指令经过网络发送到实际设备。因为领域实体自身不能完成诸如Email,网络操做等实际业务功能,故该功能只能经过某种服务完成。可是执行这个动做和其结果,流程却属于领域部分,故不能所有交由应用层来实现,不然将致使部分业务逻辑从领域层泄露。
为了解决这个问题,前后尝试了三种方式:ide

  • 使用ServiceLocate模式向领域实体中注入服务接口
  • 使用领域事件,在事件处理器重注入服务接口
  • 使用双分派模式,传入执行接口

1实体中注入服务接口

public Interface IDeviceService
{
    void Execute(string cmd);
}
public class Device
{
    private IDeviceAgent _agent = ServiceLocator.GetInstance<IDeviceService>();
    void ExecuteCmd(string cmd)
    {
        //Do something "Domian" related before sending..
        //invoke agent
        _agent.Execute(cmd);
    }
}

该模式最简单,但倒是DDD中的反模式,形成的后果是使得实体再也不“纯净”,须要依赖一个服务接口,这样将给单元测试带来麻烦,而且容忍了这种方式以后,极有可能形成后续将Repository接口等注入实体,使得领域实体进一步腐化。post

2使用领域事件

该方式下在须要定义领域事件,而在事件处理器中注入服务接口。此方法符合DDD要求,但在经典DDD分层项目中显得比较繁琐,须要频繁定义细粒度事件及事件处理器。而且调用依赖领域服务总线实现,总线消息实现为延迟传递则会带来必定问题。一样的,在这种方式下,单元测试也有必定的麻烦。单元测试

3使用双分派模式传入领域服务接口

Chassaging在这篇文章测试

If I have mail message entity and I want a Send method on it ?
Tiding your entity to the service that will use it is not conceptually satisfying. The
server >that will send the message is a medium and is not part of the entity itself.
It’s seems better to call server.Send(message).
The problem is that you can end breaking the tell don’t ask principle because the Send
method will ask the message for each property value. And you can be tempted to put
computations that should be in the message entity inside the Send method.spa

Let’s call Double Dispatch to the rescue !code

  • Design a server interface presenting a Send method that take the parameters it need (title, recipients, message body⋯)
  • Add a SendThrough method to your entity that takes the server interface as parameter
  • Implement SendTrhough so that it computes values to pass to the Send method.

That’s it.server

简单来讲,就是定义一个服务接口及其所需的参数,而后在实体中添加一个ExecuteThrough方法,将参数和接口传入,在基础层等实现该接口:接口

public class Device
{
    public void ExecuteCmdThrough(string cmd, IDeviceService service)
    {
        //Do something "Domian" related before sending..
        //Dispatch behaviors to interface
        service.Execute(cmd);
    }
}
相关文章
相关标签/搜索