DDD(一)——初识


一、引言

软件系统面向对象的设计思想可谓历史悠久,20世纪70年代的Smalltalk能够说是面向对象语言的经典,直到今天咱们依然将这门语言视为面向对象语言的基础。随着编程语言和技术的发展,各类语言特性层出不穷,面向对象是大部分语言的一个基本特性,像C++、Java、C#这样的静态语言,Ruby、Python这样的动态语言都是面向对象的语言。数据库

面向对象最初是为了解决数据隔离问题,随后的发展中才逐步对封装、继承、多态进行使用。编程

过去系统分析和系统设计都是分离的,正如咱们国家“系统分析师” 和“系统设计师” 两种职称考试同样,这样割裂的结果致使,需求分析的结果没法直接进行设计编程,而可以进行编程运行的代码却扭曲需求,致使客户运行软件后才发现不少功能不是本身想要的,并且软件不能快速跟随需求变化。后端

DDD则打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件可以更灵活快速跟随需求变化。设计模式

服务器后端发展三个阶段:服务器

UI+DataBase的两层架构,这种面向数据库的架构没有灵活性。微信

UI+Service+DataBase的多层SOA架构,这种服务+表模型的架构易使服务变得囊肿,难于维护拓展,伸缩性能差。数据结构

DDD+SOA微服务的事件驱动的CQRS读写分离架构,应付复杂业务逻辑,以聚合模型替代数据表模型,以并发的事件驱动替代串联的消息驱动。真正实现以业务实体为核心的灵活拓展。架构


二、DDD是什么?

领域驱动设计(Domain-Driven Design)简称DDD。并发

DDD是由 Eric Evans 提出的,综合软件系统分析和设计的面向对象建模方法。现在已经发展成为了一种针对大型复杂系统的领域建模与分析方法。
DDD是针对软件开发领域的一种系统与理论分析方法,是一种方法论。编程语言

领域驱动设计(DDD)的概念源于2004年著名建模专家Eric Evans发表的书籍:《Domain-Driven Design – Tackling Complexity in the Heart of Software》中文译名:领域驱动设计—软件核心复杂性应对之道,池建强在2011年发表的一篇文章《领域驱动设计和实践》中是这样形容DDD的:领域驱动设计事实上是针对OOAD的一个扩展和延伸,DDD基于面向对象分析与设计技术,对技术架构进行了分层规划,同时对每一个类进行了策略和类型的划分。(OOAD:面向对象的分析和设计)

OOAD经常使用基本的设计原则有七个:

  1. 单一职责原则(Single Responsibility Principle,SRP)类的职责要单一,不能将太多职责放在同一个类中.
  2. 开闭原则(Open-Closed Principle, OCP)对扩展开放,对修改关闭。软件设计应该尽量的使架构稳定并且又容易知足不一样的需求,提升代码可重用性。理论上但愿能达到不修改源代码的前提下扩展功能。
  3. 里氏代换原则(Liskov Substitution Principle,LSP)在系统中,一个能够接受基类对象的地方必然能够接受一个子类对象。
  4. 依赖倒转原则(Dependency Inversion Principle,DIP)要针对抽象编程,而不是针对具体类编程.
  5. 接口隔离原则(Interface Segregation Principle,ISP)使用多个专门的接口来取代一个统一的接口.
  6. 合成复用原则((Composition/Aggregate Reuse Principle,CARP)系统中尽可能使用组合和聚合的关系,而尽可能少用甚至不用继承关系。
  7. 迪米特法则(Law of Demeter, LoD)一个软件实体应当尽可能少的与其余实体发生相互做用.又叫作最少知道原则。也就是说一个对象应当对其余对象要尽量少的了解,不要和陌生人说话。

在面向对象中的基本设计原则基础上,又出现了各类各样的设计模式,来解决同一种问题。

DDD和已有方法的区别是什么?

传统方法:

是针对数据库建模,是关系型数据库理论的延续,关注数据表和数据表之间的关系,是面向技术建模。

DDD:

将业务概念和规则转变为软件系统中的类型及其属性和行为

合理利用面向对象的封装、继承、多态等设计要素

下降或隐藏系统的业务复杂度

提高系统扩展性

传统的开发是面对数据库表,先设计表结构,再研究表与表之间的关联。DDD开发是先理解业务,再理解页面,再经过页面来构想代码中的业务流程,以此来设计数据库表。

DDD相关概念

  1. 领域(Domain):

现实世界中,领域包含了问题域和解系统。通常认为软件是对现实世界的部分模拟。在DDD中,解系统能够映射为一个个限界上下文,限界上下文就是软件对于问题域的一个特定的、有限的解决方案。

  1. 限界上下文(Bounded Context):

一个由显示边界限定的特定职责。领域模型便存在于这个边界以内。在边界内,每个模型概念,包括它的属性和操做,都具备特殊的含义。

限界上下文之间的映射关系

  • 合做关系(Partnership):两个上下文紧密合做的关系,一荣俱荣,一损俱损。

  • 共享内核(Shared Kernel):两个上下文依赖部分共享的模型。

  • 客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。

  • 遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。

  • 防腐层(Anticorruption Layer):一个上下文经过一些适配和转换与另外一个上下文交互。亦称适配层。在一个上下文中,有时须要对外部上下文进行访问,一般会引入防腐层的概念来对外部上下文的访问进行一次转义。

  • 开放主机服务(Open Host Service):定义一种协议来让其余上下文来对本上下文进行访问。

  • 发布语言(Published Language):一般与OHS一块儿使用,用于定义开放主机的协议。

  • 大泥球(Big Ball of Mud):混杂在一块儿的上下文关系,边界不清晰。

  • 另谋他路(SeparateWay):两个彻底没有任何联系的上下文。

  1. 通用语言:

在开发一个项目时,参与的人不少,有开发人员,有测试人员,常常会出现的一个问题就是测试不明白开发的某个字段,某个类名,某个接口是什么意思,开发与开发之间也会出现相似的问题,而通用语言就是为了解决这一问题。顾名思义,通用就是说你们都用,你们都用就能保证一致性,好比:userinfo,一看就知道是用户信息的含义。

  1. 实体(Entity):

实体能够理解为传统项目中的实体类,所承担的责任基本一致,区别就在于传统项目是针对数据的,实体就是实体没有其余任何做用,而DDD中的实体则是能够认为是一个领域,是包含业务的。实体不是由于某个属性才是实体,是由于业务需求。

  1. 值对象(Value Object):

当一个对象用于对事务进行描述而没有惟一标识时,它被称做值对象。它具备不变性、相等性和可替换性。

  1. 领域服务(Domain Service):

一些重要的领域行为或操做,能够归类为领域服务。领域服务自己所承载的职责是经过串联领域对象、资源库和防腐层等一系列领域内的对象的行为,对其余上下文提供交互的接口。

  1. 领域事件:

领域事件是对领域内发生的活动进行的建模。领域事件有因有果,可是必须是有价值的缘由才有果。

  1. 聚合(Aggregate):

聚合是一组相关对象的集合,做为一个总体被外界访问,聚合根(Aggregate Root)是这个聚合的根节点。聚合由根实体,值对象和实体组成。核心领域每每都须要用聚合来表达。

从上面所述,咱们能够得知,DDD不能帮助咱们完成某个功能,不能解决某种业务需求,那么DDD究竟是什么,所能作到是什么呢?DDD分工明确,实体就是实体,领域就是领域,各自负责各自的工做,就像老板招工人,一通乱找确定须要花费更多的时间和精力,可是分工明确的话,人事部招作人事工做的,开发部招收作开发的,这就能更少的花费时间和精力了。因此DDD是一种解决问题的方法,是一种解决问题的想法,是一种简化开发流程的设计,因此DDD的实现是先于开发的,是在设计过程当中就实现的。


三、DDD的好处

在业务初期,功能大都很是简单,普通的 CRUD 就基本能知足要求,此时系统是清晰的。但随着产品的不断迭代和演化,业务逻辑变得愈来愈复杂,咱们的系统也愈来愈冗杂。各个模块之间彼此关联,甚至到后期连相应的开发者都很难说清模块的具体功能和意图究竟是什么。这就会致使在想要修改一个功能时,要追溯到这个功能须要修改的点就要很长时间,更别提修改带来的不可预知的影响面。

举个例子:

订单服务中提供了查询、建立订单相关的接口,也提供了订单评价、支付的接口。同时订单表是个大表,包含了很是多字段。咱们在维护和升级时,将会致使牵一发而动全身,极可能本来咱们只是想改下评价相关的功能,却影响到了建立订单的核心流程。虽然咱们能够经过测试来保证功能的完备性,但当咱们在订单领域有大量需求同时并行开发时将会出现改动重叠、恶性循环、疲于奔命修改各类问题的局面,并且大量的全量回归会给测试带来不可接受的灾难。

传统项目Service层很重,全部逻辑处理基本都放在service层。随着系统的升级,不断的重构,业务愈来愈多,愈来愈庞杂,包括数据结构的变化,那么各个模块就须要进行修改,本来清晰的系统通过不断的演化变得复杂、冗余、耦合度高,后果就很是严重。

再举个例子:

一个商城系统,有购买商品支付,跟踪邮件等等一些列的流程,这个时候忽然须要加入会员功能,也要生成订单,生成支付,几乎与实物商品的订单一致,惟一不一样的是会员不能退款,若是咱们从新写一个支付流程,这无疑是浪费大量的时间和精力去作重复的事情。除此以外若是咱们还有别的办法,咱们可使用实物订单的生成订单和支付方法,就能够轻松的完成会员这个功能,若是哪一天经理忽然说不须要这个功能了,就算修改,对整个系统而言也无伤大雅。

DDD能让咱们知道如何抽象出限界上下文以及如何去分而治之。

分而治之 : 把复杂的大规模软件拆分红若干个子模块,每个模块都能独立运行和解决相关问题。而且分割后各个部分能够组装成为一个总体。

抽象 : 使用抽象可以将问题由大化小,并且问题越小越容易理解,好比说咱们要对接支付,抽象的纬度应该是支付,而不是具体的微信支付仍是支付宝支付。

DDD 的限界上下文能够完美匹配微服务的要求。在系统复杂以后,咱们都须要用分治来拆解问题。通常有两种方式,技术维度和业务维度。技术维度是相似 MVC 这样,业务维度则是指按业务领域来划分系统。 微服务架构更强调从业务维度去作分治来应对系统复杂度, 而 DDD 也是一样的着重业务视角。

相关文章
相关标签/搜索