应用服务和领域模型的边界在哪里?

爱⌒轻易说出口 提交于 2020-02-07 18:39:11

应用服务和领域模型的边界在哪里?

处理边界往往是一个比较棘手的问题。就像处理三八线一样,有的时候你会感觉对方的地盘属于你的,对方又感觉你的地盘属于他,然后要求重新重新划分。边界往往就是这样,经常出现冲突。

应用服务和领域模型的边界就没有像两个思想作怪那么复杂,因为他们具有规则和逻辑。所以只要弄懂什么是服务,什么是领域模型就可以解决这看似混乱的边界。

应用服务与领域模型的产生

应用服务和领域模型的出现是软件开发历史进程中的产物。在最开始的领域逻辑是混沌的,并没有领域模型,只是简单的事务脚本。在这个时期,一个脚本就对应一个业务用例。对于简单的业务来说这没什么问题,而且还很方便。但是当事务脚本中操作的模型对象超过两个以上,这时事务脚本就变得复杂起来,他完成了这些模型对象所有的业务逻辑。在这个时期事务脚本担任着全部的业务逻辑。随着业务复杂性的增加,人们解决问题域的抽象也变得更加接近现实。此时非过程化的面向对象编程也逐渐流行起来,所以也是时候将事务脚本的业务逻辑交给领域模型来解决了。从此事务脚本被一分为二,领域模型反应了细粒度业务逻辑,但是细粒度的领域模型在使用的过程又比较麻烦且繁琐,我们的业务流程常以粗粒度的用例模型来表达,所以我们需要一组类将细粒度的领域模型封装成粗粒度的用例模型供客户调用,这组封装的用例模型类叫做应用服务类。

应用服务包含什么内容?

上面是从业务的角度分析应用服务的产生,这是主要的产生原因,接下来还要从技术的角度来讲解应用服务中的内容。

1、数据库事务,这方面大家接触颇多,就不过多的介绍。

2、服务方法形参,如果参数数量不多,你可能会直接写到方法形参上。但是参数多的时候,你可能会用一个DTO来封装参数。在我看来用DTO作为形参并不是一个好的模式。

我为什么会认为DTO封装方法形参不是一个好的模式?

为什么需要DTO作为形参,因为参数多。看似多么合理的理由。

我将应用服务方法分为执行动作型和操作属性型。

操作属性型方法主要是对实体属性的操作,这看上去好像是数据模型,没错,此时此刻,在此上下文环境中主要就是在更新属性。(有一个误解就是面向对象中的类包含属性和方法,但他们都不是必须的。并不是说类中没有方法就不是领域模型了,领域模型是根据业务分析设计的,他是反映的业务,而不是一味的技术技巧)。当你对属性型方法参数封装成DTO仅仅是做对实体属性的复制,这并没有什么实用意义,要是这样为什么不直接使用实体类作为参数呢。多此之举,虽然一样可以实现需求,但这并不是使用它的理由。

3、权限安全,任何事物都需要一堵防御墙,才能保证内部的稳定性。应用服务也一样需要,关于安全方面有两种方式:基于角色的访问控制(RBAC),这是一个粗粒度的访问控制,他根据用户所拥有的角色来判断是否有访问权限。另一个是访问控制列表(ACL),这是一个细粒度的访问控制,他根据用户对某一条记录的操作权限来判断是否有访问权限。例如用户对文件的操作权限、LDAP中entry的权限控制都是使用的ACL。在应用开发方面,Spring Security同时支持RBAC和ACL两种方式。

4、应用服务方法返回值,方法返回值和形参很像,但是对于两者的DTO封装,有一种说法是为了将视图层和领域层通过应用层隔离开,让领域模型不外泄。这种想法是不切实际的,如果返回值DTO和要返回的真实领域模型不一致,那就缺乏完整性,如果一致又何必需要使用个DTO再次封装,直接返回要返回的领域模型不就行了。

问题解答

很多人说我在用命令对象(XxxCommand)作为形参?

嗯哼,并不是命名为XxxCommand就是命令对象,这种用于传参的XxxCommand和DTO有什么大的区别吗?

那应该在哪里实施DTO呢?

视图层。现在的视图展示有了很多方式,比如:RESTful,GraphQL,HTML等等。在这一层才是将领域模型转换为应对具体端口DTO的地方。

总结

我从软件开发历史和业务的角度将事务脚本分解成应用服务和领域模型的由来。又从技术的角度对应用服务的形参、事务、权限、返回值几个方面做了一些讲解。与其说应用服务和领域模型的边界问题不如说他们之间的调用关系。

更全面的内容可以参考《企业应用架构模式》p.93。

如有问题请加QQ群讨论:

image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!