对 DDD 的总结与思考(一)

我的 boss 曾经问过我一个很基本的问题:你觉得如何划分一个项目的结构?

我想现在的我依然很难回答这个问题。尽管目前对于纯技术的资料已经汗牛充栋,对于架构设计却依然是一门隐学——我们大都在意的是数据库如何拆分,服务如何设计之类。火热的微服务也只是一种实现上,软件层的拆分,而不是逻辑层的分离。DDD 其实是软件知识体系中的哲学,它是无关于任何技术学科,比如数据库、分布式甚至是软件工程的,它只是一个解决问题的策略

在《Java 编程思想》中,所有事物都看做是对象。对象有状态和方法,通过方法来进行协作,这是面向对象语言的基本常识。但是,这里没有涉及到如何对复杂场景建模——尤其是,考虑到许多技术细节,比如持久化的时候。

贫血模型也许得益于 Ruby on Rails 及其理念的流行(不过也有一些理念仍然是十分有价值的,比如约定大于配置)。ORM 框架会对所有数据库表做 E/R 映射,但这不改变二者阻抗失配的问题。当你以这个贫血模型为中心进行设计时,就已经陷入了反 DDD 的模式,也就是面向数据,或者说面向过程——因为全程我们盯着的都是关系数据库,或者缓存,whatever。

Martin 对业务逻辑层,也可以说是领域层总结了 4 种常见的模式:

事务脚本就是刚入门的人会写出来的代码,正如他的名字一样是充满脚本风格的。表模块这个概念有点突兀,它的定义是使用一个实例来表示所有的数据库行,可以理解为指的就是.NET 里的DataTable(在我浅薄的 Java 编程经历中,似乎 Java 没有DataTable这样的设计)。总之,一个对象代表一张表。显然,这样做有很强的动态性。用过DataTable,或者是用过动态语言比如 Python 的人很容易察觉到这一点。就像 Martin 说的,这种模式其实是把数据库当做一个黑盒子,而且这个黑盒子的代码还得自己写。

Service则是一个被后端广泛接受的术语。所有后端项目你都可以看到类似的层,尤其是 Spring 这样的框架直接将其视为一种约定——有时候也可能叫做Dubbo。从概念上,Service层只是对业务逻辑层的调用,以及这个调用逻辑的复用,而不涉及任何逻辑本身。不过,也有很多人习惯在Service层实现业务逻辑,究其原因,这是由于一种贫血模型(Anemic Domain Model)的风格导致的。

在我曾经开发的项目中,就曾使用了这种方式。贫血模型和 DDD 所倡导的充血模型是截然相反的:

需要注意的是,实体一词还被用在数据库理论的 E/R 模型中,同时被 ORM 所广泛采用。这和 DDD 的 Entity 是不对等的。

an object fundamentally defined not by its attributes, but by a thread of continuity and its identity.

DDD 术语实体代表的不是属性的集合,而是一个唯一标识的对象。作为程序员很容易把这里的 thread 当成是线程——当然,它是原本这个单词的含义,线。有一种典型的风格是增加一个Entity的基类或者接口(更加 Engineering 的方式是既有接口也有基类),在这个Entity中包含一个Id字段。有时候,我们还会将一些时间快照的功能加入其中,比如创建日期、修改日期、版本号、软删除之类。

将业务逻辑移动到模型中,究竟会有多大的好处呢?至少它更符合面向对象的原则了,而且由于逻辑集中在了领域对象上,所以代码的模块化更好,更容易测试。

转载于:https://juejin.im/post/5ca16aaff265da30ac219fa5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值