系统设计 — 领域层的组织

目前的领域逻辑的组织可以分为三种:
一 事务脚本:
这个是我们最为常见的构建方式,简单的说:从表示层接受到参数,进行校验,计算,在将数据存储到合适的数据源层。然后再给表示层一个合适的返回,基本上是一个过程对应一个用户的可能的一个动作,在多个行为之间可以抽取出子例程在不同事物脚本之间共享!
优点:

  • 简单,目前大多数开发者使用的方式
  • 能够很好同行数据入口或是表数据入口的简单数据源层很好的协作
  • 设定事物边界的方法显而易见,一个事务始于其脚本的开始,终于其脚本的关闭

缺点:
前面也提到了,当在多个事务脚本中存在相同代码的时候,可以抽取出公共的子例程,但是这里有两个问题,一我们需要知道何时出现了副本,二我们如何取消除副本 这两个都是比较头疼的问题。

二 领域模型:
领域模型的出现就是为了解决事务脚本的缺点,我们以名词为构建方式,抽象出对象的概念,将该对象相关的计算和验证放入对象自身内部,这样原本一个完整的行为会分布到各个名词对象中。
优点:
在业务逻辑复杂度较高的情况下,解决了事务脚本中的副本发现和消除

缺点:
需要一定的思维适应,若是领域建模的不好,反而会适得其反
同数据库之间的映射复杂度变高,一般需要数据映射器,常见的做法是在领域对象和数据库间加上实体对象,通过全自动或是半自动的ORMapping工具。

跨领域的行为处理
一般有两种方式,一是在领域对象中调用另一领域对象,二是在各个领域对象之上抽取一个外观的SERVICE,在这个SERVICE层面统一调度,具体后面还会提到。

三 表模块:
这种构建方式类似于领域模型,但是有点稍微的不同,领域模型是数据库中每一个数据对应一个实例,而表模型只有一个公共的实例。举例子来说,一个定合同的行为,我们会生成合同类,产品类、收入确认类。
表模块的方式通过合同类从数据库中拉取一个合同的记录集,然后通过传递这个记录器给产品类来完成费用的计算,最后将计算的结果通过收入确认类插入到数据库中,若是只计算其中一个合同的费用,那么接需要传递一个合同的ID给产品类!
领域模型的方式每次只传递一个合同记录给产品类来完成费用的计算,再将结果通过收入确认类来插入到数据库中。(同时领域对象可能不等同于实际的表结构)
事务脚本是通过数据源层获取一个记录集,再计算费用,最后插入数据库中,并不会将不同的动作区分到不同的领域对象中。

优点:
对比上面的三种方式,可以看出表模块是事务脚本和领域对象的中间地带,做了分类行为处理,但是更灵活的采用的是记录集的方式来处理!围绕表来而非围绕行为来组织领域逻辑,同时更容易的发现和移除冗余代码。很好很直接面对我们的表数据!这种方式也是比较常见的开发模式!

缺点:
因为围绕的是表记录集,最小单位不是领域对象,所以不能细粒度的组织逻辑结构,很难去使用一个继承、组合和其他面向对象的设计模式。

如何选择:
对于一些简单的业务场景,完全可以使用事务脚本的方式来做,若是业务有一定复杂的话,那么还是推荐使用领域对象,如何判断复杂,还是需要根据自己平时的工作经验,或是请教资深的开发人员,至于表模块的话,取决于是否拥有一个记录集的工具,目前现在的ibaits和hibernation都能很好的支持记录集的数据获取,读过DDD的人大多还是处在这种模式下,目前看到的代码中。当然这三者也可以同时使用,但是我个人根据设计代码风格的一致性考虑的话,还是尽量的统一,虽然会付出一定的陈本(个人偏好而已)

领域层的组织
上面说了这么多,那么该如何具体组织领域层,若是事务脚本的话,就毋庸置疑了,简单的一个service搞定一切,若是领域模型或是表模块的话,那么就需要将服务层单独的剥离,置于底层的领域模型或是表模块之上,服务层中处理事务、安全、基础的校验等等。
有种做法是服务层包含所有的业务逻辑,以事务脚本方式组织,下层的领域对象变成实体对象,简单的POJO,并与数据库记录一一对应。

还有种做法是 控制器–实体风格,就是将每个用例或是行为特有的逻辑放到一个控制器类中,将各个不同共性的行为组织到领域对象中,这种做法最典型的案例就是MVC。这个控制器可以称之为:用例控制器或是应用控制器。
这种做法是将行为分不到事务控制器和领域对象中,如此还是会产生冗余代码。

简单总结的说:将逻辑层分为两层,在服务层尽量减少业务逻辑,让他只负责安全、事务等事宜,而将业务逻辑落到领域对象中,最小化服务层,对外暴露的接口是基于用例!

对于表模块和领域对象区别:
还是拿合同的用例说来,在服务层中若是面对一个记录集,是先生成一个合同类,并将记录集一次性传递给产品类,而领域对象是获取一个记录集后,循环的调用产品类来处理数据!

作者: inter12

在这苦短的人生中,追求点自己的简单快乐

发表评论

电子邮件地址不会被公开。 必填项已用*标注