从域对象中分离技术

时间:2011-12-12 15:13:42

标签: wcf domain-driven-design prism

我公司有一个应用程序,允许用户执行测量循环血量的诊断医学测试。该测试涉及使用伽马计数器来测量/计数多个血液样本中的辐射。将这些样品放在电动转盘(即样品转换器)中,将样品移到γ计数器上进行计数。

以下是我们认为域名的所在:

  • 测试(即血容量,质量控制)
  • 患者
  • 样本(即要计算的东西)
  • 测试执行上下文(即,样本的规范及其对应于某种类型的测试的顺序)

我们相信我们的域名动词是:

  • 将轮播移动到指定位置
  • 获得光谱(即计数样品)
  • 运行测试

当我们了解域驱动设计时,业务逻辑应该在中。我们的业务逻辑主要依赖于我们所谓的测试执行控制器。该控制器使用测试执行上下文来确定如何将样本移动到位并让伽玛计数器测量它们。

让我们感到困惑的具体技术是Prism和WCF。

(1)Prism依靠事件聚合器在系统周围传递非CLR事件。测试执行控制器使用它来让系统的其他部分知道发生了什么(例如,正在计算样品2A,当前测试剩余34分钟)。从技术上讲,事件聚合器是技术,它是Prism的一部分,域对象/服务不应该依赖于技术。

问题:有没有办法对事物进行重组,以便我们的域名服务不依赖于技术?

(2)我们有两个WCF服务,允许我们与样本转换器和gamma计数器进行通信。每个服务都有一个契约(即一个用WCF特定属性修饰的界面)。至少在合同中,我们将关注点分开,以便我们的主要应用程序依赖于行为,而不是特定的样本更换器或gamma计数器。但是,WCF是技术,应用程序代码需要知道我们正在与之交谈的这个服务是WCF服务(通过创建代理类来完成)。为了满足DDD约束,我们最终得到了几个类似命名的类/接口似乎是多余的。这是一个例子

  • IGammaCounterService - 定义与gamma计数器通信的方法的WCF合约。该接口由(1)实际实现所在的WCF方面以及(2)与该服务对话的应用程序代码引用。
  • IGammaCounter - 定义伽玛计数器行为的属性/方法集。 (这是我们域名的一部分。)
  • GammaCounterProxy - 实现WCF服务合同的类。这是我们的应用程序用来与WCF服务通信的内容。
  • GammaCounter - 业务逻辑使用的类。这是一个GammaCounterProxy(通过继承),也实现了IGammaCounter。 (注意:我们使用控制容器的反转 - 特别是Unity - 在我们的应用程序中注册此实例。)

问题:我们在域和WCF端具有基本上具有相同方法名称的接口。是否有更好/更清洁的方法来做到这一点?

2 个答案:

答案 0 :(得分:2)

WCF可以让您通过端点公开您的服务来很好地区分您的问题。这些端点可以支持:

  • 一个或多个传输(例如TCP,HTTP,命名管道,MSMQ)
  • 一种或多种编码格式(二进制编码的XML,XML,JSON)
  • 零个或多个其他问题(例如对WS- *的支持)

例如,在我的Magic8Ball WCF sample中,我同时通过几个端点公开Magic8Ball服务:binary-XML / TCP用于(非常)快速访问WCF客户端,XML / HTTP用于非WCF客户端,JSON / REST客户端的HTTP。

如果您愿意,可以在app.config中完全表达这些端点配置,这样您就不必修改源代码&如果您的环境需要改变,请重建/重新部署您的服务。

因此,您的每个“控制器”都可以作为服务公开,每个名词都可以作为可序列化的数据实体公开。如果您从名词中消除了除最基本的业务逻辑之外的所有业务逻辑,那么任何平台上的任何调用应用程序都应该能够形成格式正确的消息,其中包含以正确格式编码的数据,并通过支持的传输将其传递给您的服务。

通过这种方式,您可以实现大量的技术抽象,以便您在将来选择使用不同的技术/平台构建系统的某些部分时,您的环境中的任何内容都不应该只关心有线协议坚持。

答案 1 :(得分:0)

解决方案中需要考虑的另一个结构轴是应用程序层集。例如,在这种情况下,您似乎有一个表示层(使用Prism / WPF实现),一个服务层(由WCF实现)和一个业务/域层(使用DDD实现)。

  

有没有办法重组事物,以便我们的域服务不是   技术依赖

如果测试执行控制器是MVC意义上的控制器,那么它不应包含业务逻辑。相反,它的工作是协调UI和业务层之间的交互。在这种特定情况下,控制器应该通过WCF实现的服务层将命令转发到业务层。但是,控制器本身是表示层的一部分,因此它依赖于技术特定组件(例如事件聚合器)这一事实不是问题,因为您已经选择WCF / Prim作为表示层的技术 - 没有必要抽象它,特别是过早地。

  

我们在域和WCF方面基本上都有接口   具有相同的方法名称。是否有更好/更清洁的方法来做到这一点?

通常,当DDD业务层通过WCF作为服务公开时,会产生这种类型的双类层次结构,因为您创建映射到域实体和值的DTOs(数据协定)。 DTO没有行为,它们的核心作用是表示进出服务的数据。很多时候,DTO看起来与相应的域对象非常相似,并且可以接受这种复制。如果这仍然是一个问题,您可以查看映射库,如AutoMapper

就组织解决方案而言,您有几个选择。一种是完全隐藏域层与表示层,并且只允许通过服务层访问它。因此,表示层项目(WPF / Prism)将引用包含服务合同和相关数据协定(DTO)的精简项目。这可以是一个小项目,它定义服务层的“模式”。该项目也将由实现服务合同的WCF项目引用。这种方法的好处是域完全由服务层封装。您可以通过重新部署服务来更改服务合同的实现 - 无需重新部署表示层。缺点是它可能过度,或者可能不适合将域作为服务公开。

另外,我对你的命名约定和结构感到有些困惑。例如,GammaCounterProxy不是代理,当您获得对服务契约IGammaCounterService的引用时,代理由WCF生成。服务实现类本身只是一个实现,而不是代理。此外,GammaCounter继承GammaCounterProxy似乎是错误的。 GammaCounter直接实现IGammaCounter更有意义,并且GammaCounterProxy使用该对象(重命名为GammaCounterImpl)。 GammaCounterImpl的工作是处理一些命令(由DTO参数表示)。它可以通过加载所有适当的域对象(例如GammaCounter),在它们上调用方法,然后可能返回结果(作为DTO)然后由表示层处理来实现。