SlideShare ist ein Scribd-Unternehmen logo
1 von 109
Downloaden Sie, um offline zu lesen
领域驱动设计实践 @
       瑞友科技IT应用研究院池建强
                     Twitter: @sagacity
                       Weibo: @池建强
             Mail: jackychi@gmail.com
About ME
•   池建强,70后程序员,98年毕业,先后就职于洪恩软件、
    RocketSofeware和用友集团-瑞友科技,现任瑞友科技IT应用
    研究院副院长

•   先后从事互联网和企业应用开发,目前致力于基础应用平台
    的研究

•   热爱技术和编码工作,坚持年轻时的理想,倒霉的乐观者

•   技术领域:Java、Python、Ruby、Objective-C、DDD、
    OSGi、App Platform
模型是抽象的
                 现实是形象的
                 技巧是重要的
                 思想是永恒的




Domain	
  Model	
  -­‐	
  What	
  Why	
  How?
从软件系统诞生之
初,程序设计者就开始
梦想有⼀一天能够像建造
桥梁和房屋那样“透
明”的构造软件,让现
实和代码对应起来
软件开发总是比任何人估计的慢,如果不是有意
的放宽项目期限,几乎不会出现提前完成的软件项目
和产品。有时候我们必须耐下心来把所有琐碎的、困
难的、细节的问题都解决并不断打磨,才能完成,有
时候没有别的办法,只能等待
⼀一个案例
2010-01       2010-03
                        2010-05
                                   ......   2010-12

    采用领域驱动的
     方式开发




                幸福的时光总是短暂的......
2010-01       2010-03
                        2010-05
                                   ......        2010-12

    采用领域驱动的                           商务要求尽快出⼀一
     方式开发                                个版本


2010-01       2010-03
                        2010-05
                                  ......         2011-04



                                             好日子结束了
                                            苦逼的总是开发者
领域驱动设计不是用来解决开发速度的
领域驱动设计是用来解决软件核心复杂性的
面向对象的分析设计
软件系统面向对象的设计思想可谓历史悠久,20世纪70
年代的Smalltalk可以说是面向对象语言的经典,直到今
天我们依然将这门语言视为面向对象语言的基础
面 向 对 象 是 大 部 分 语 言 的 ⼀一 个 基 本 特 性 , 像C++、
Java、Objective-C这样的静态语言,Ruby、Python这
样的动态语言都是面向对象的语言
2004年著名建模专家Eric Evans发表了他最具影响力的书籍
《Domain-Driven Design》
   ——Tackling Complexity in the Heart of Software
中文译名:领域驱动设计—软件核心复杂性应对之道,书中
提出了“领域驱动设计(简称 DDD)”的概念。
领域驱动设计事实上针对是OOAD的⼀一个扩展和延伸,DDD
基于面向对象分析与设计技术,对技术框架进行了分层规
划,同时对每个类进行了策略和类型的划分
采用DDD的设计思想,业务逻辑不再集中在几个大型
的类上,而是由大量相对小的领域对象(类)组成,这
些类具备自己的状态和行为,每个类是相对完整的独立
体,并与现实领域的业务对象映射。领域模型就是由这
样许多的细粒度的类组成
领域驱动设计是技术人员和领域专家沟通的桥梁
技术人员和领域专家沟通的桥梁是领域驱动设计
 技术人员 领域驱动设计 沟通 领域专家 桥梁
public	
  interface	
  IBookService	
  {



                                                         û
	
  	
  	
  	
  double	
  submitOrder(int	
  orderId);
}
                                                 不容易理解的抽象


public	
  interface	
  IBookService	
  {
	
  	
  	
  	
  double	
  submitOrder(Order	
  order);
}
                                                         ü
抽象 - 打折策略
领域模型和事务脚本
事务脚本(Transaction Script)的核心是过程,每个过程处理来
自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,
从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql
语句来实现数据库信息的处理
事务脚本(Transaction Script)的核心是过程,每个过程处理来
自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,
从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql
语句来实现数据库信息的处理
事务脚本把业务逻辑组织成单个过程,在过程中直接调用数据库,
业务逻辑在服务(Service)层处理
Action处理UI层的动作请求,将Request中的数据组装后传递给
BusinessService,BS层做简单的逻辑处理后,调用数据访问对
象进行数据持久化,其中VO充当了数据传输对象的作用,只具
备getter和setter方法,没有状态和行为

                                  Transaction Script
效果?后果?看代码
事务脚本模式的特点是简单容易理解,面向过程设计。
事务脚本模式的特点是简单容易理解,面向过程设计。
 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良
好,容易理解,而且⼀一个事务的处理不会影响其他事务。
事务脚本模式的特点是简单容易理解,面向过程设计。
 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良
好,容易理解,而且⼀一个事务的处理不会影响其他事务。
  不过缺点也很明显,对于复杂的业务逻辑处理力不从心,难以保
持良好的设计,事务之间的冗余代码不断增多,通过复制粘贴方式
进行复用。可维护性和扩展性变差。
Smart UI-反模式
 ——在用户界面中实现大部分业务逻辑
领域模型(Domain Model)

‣面向对象分析和设计
‣领域模型具备自己的属性行为状态,并与现实世界的业务对象相映射
‣各类具备明确的职责划分,领域对象元素之间通过聚合和引用等关系配
合解决实际业务应用和规则
‣可复用,可维护,易扩展
‣可以采用合适的设计模型进行详细设计
‣要求设计人员有良好的抽象能力
Domain Model
我们也来看代码
在实际的设计中,我们需要根据具体的需求选择相应
的设计模式。具备复杂业务逻辑的核心业务系统适合
使用领域模型,简单的信息管理系统或大数据处理可
以考虑采用事务脚本模式
领域驱动设计元素
• 成熟、清晰的分层架构
分层架构   • 领域对象与现实世界的业务映射
       • 明确的职责划分



       • 领域对象是核心
 复用    • 领域对象复用:完整的业务对象描述
       • 设计复用:设计基于领域对象而非数据库




       • 具备复杂业务逻辑的软件开发
       • 对设计和开发人员要求较高
使用场景
       • 不适用普通CRUD的业务
       • 软件的维护性和扩展性良好
分层架构
名称                  职责

 展现层    负责向用户展现信息以及解释用户命令

        很薄的⼀一层,用来协调应用的活动。它不包含业务逻辑。它不保留
 应用层    业务对象的状态,但它保有应用任务的进度状态
        本层包含关于领域的信息。这是业务软件的核心所在。在这里保留
 领域层    业务对象的状态,对业务对象和它们状态的持久化被委托给了基础
        设施层。
        本层作为其他层的支撑库存在。它提供了层间的通信,实现对业务
基础设施层   对象的持久化,包含对用户界面层的支撑库等作用
实体,值对象,服务
En#ty(实体)—	
  人/座位-­‐先到先得?
Value	
  Object(值对象)—画笔/地址
name




       *
Services(服务)
Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实
世界业务对象
Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实
世界业务对象
Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时
对象,可以用来传递参数或作为实体的属性,也可以封装复杂的
计算逻辑
Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实
世界业务对象
Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时
对象,可以用来传递参数或作为实体的属性,也可以封装复杂的
计算逻辑
Services:为上层建筑提供可操作的接口,负责对领域对象进行
调度和封装,同时可以对外提供各种形式的服务
领域模型的生命周期
关系数据库
                                  面向对象数据库
                                    NoSql

          创建
                    存储

修改   活动状态                   数据库

                    重建

     删除        归档



                         数据库或文件
               删除
Factory和Repository基于Aggregate,对特
定生命周期转换的复杂性进行了封装
Aggregate(聚合)
什么是聚合,我们来画⼀一下
Item        Product




<<IPaymentStrategy>>




      CashPay          CreditCardPay




                                       Aggregate	
  root
Factory	
  -­‐	
  IoC
<beans>
    <!--Volvo是ICar的实现类 -->
    <bean id="vcar" class="Volvo">
    </bean>
    <!--为驾驶者提供用车,依赖注入-->
    <bean id="oneDriver" class="Driver">
        <property name="car">
            <ref bean="vcar"></ref>
        </property>
    </bean>
</beans>                   public Driver{
                               private ICar car;
                               public Driver(){
                               }
                               public void drive(){
                                    car.method();
                               }
                               //getter and setter
                           }

                           Driver drive = helper.getBean( "oneDriver" );
                           drive.drive();
Repository
‣ 操作持久对象并管理其生命周期
‣ 领域对象和持久化解藕
‣ 封装持久化技术
 ‣ 多数据源、连接池、数据源访问代理
 ‣ O/R Mapping技术
 ‣ NoSql
 ‣ 分布式文件系统
‣ 持久化层可替换
来自QCon淘宝的分享
规则引擎的案例
领域元素
‣ Package——规则包
‣ Rule——规则
‣ Attribute——规则属性
‣ When/Then——条件
‣ ......
如何实现这样⼀一个设计呢?
    看例子吧
⼀一些原则
表意接口


Inten#on	
  Revealing	
  Interface
如果⼀一个开发人员为了使用⼀一个组件必须要去研究
    它的实现,那么就失去了封装的意义
无副作用函数


 Side-­‐Effect-­‐Free	
  Func#on
所谓"副作用"(side effect),指的是函数内部与外部互动
(最典型的情况,就是修改全局变量的值),产生运算以外
的其他结果——函数式编程?
所谓"副作用"(side effect),指的是函数内部与外部互动
(最典型的情况,就是修改全局变量的值),产生运算以外
的其他结果——函数式编程?
利用VO的不变性,创建无副作用的函数,例如,传入或返回
的对象是by value,而不是by reference,对返回值的修
改,不会影响原来的对象。
Conceptual Contour
    概念轮廓
通过坝或其他手段把⼀一个湖分割为几块,在任何⼀一块中投入
石子都不会影响其他部分。
把设计元素(行为、接口、类、聚合等)分解为内聚单元。
通过重构,找出模型中经常变化的部分和基本稳定的部分。
如何实现组件之间的解耦
ESB也是⼀一种方式,但是远程调用?事务?
       设计时需要慎重选择
小结⼀一

表意接口把对象描述成有意义的单元。
无副作用函数让我们可以安全的使用这些单元。
概念轮廓让这些单元更稳定,更符合直觉,更容易组合
小结二

低耦合是对象设计的⼀一个基本要素,尽可能保持低耦合。把其他所
有无关的概念提取到对象之外。消除所有不重要的依赖。
限制交叉依赖的方法:
  1、子系统
  2、模块化
  3、聚合
  4、单向关联
领域模式
Specifica#ons
‣ 规约是⼀一种布尔断言
‣ 规约是业务规则的⼀一部分
‣ 理论上规约类中的方法只有⼀一个:IsSatisifedBy( Object )
‣ 规约用来测试对象是否满足某种条件,用来进行对象查询,
也可以作为某个对象的创建条件
‣ 单⼀一规约规则。多个规约通过组合表现复杂的规约
增加规约:
public class BookShelf {                1、不同作者的书放到相应
    private List books;                 的书架
                                        2、不同类型的书放到相应
    public BookShelf(){
                                        的书架
        books = new ArrayList();
    }

    public void addBook( Book book ){
        books.add(book);
    }
}
引入规约   <<Specification>>
public class AuthorSpecification implements
Specification {

    private String author;
    public AuthorSpecification( String author ){
        this.author = author;
    }

    public boolean isSatisfiedBy(Book book) {
        return ( book.getAuthor().equals(author) );
    }
}


public void addBook( Book book ){
   if ( validate( book ) )
        books.add(book);
}

private boolean validate( Book book ){
    AuthorSpecification as = new AuthorSpecification( author );
    TypeSpecification ts = new TypeSpecification( type );
    return ( as.isSatisfiedBy(book) && ts.isSatisfiedBy(book) );
}
边界上下文


    Bounded	
  Context
明确的定义模型所应用的上下文。根据团队的组织、软件系统的功
能和物理表现(代码数据库)来设置模型的边界。在这些边界中严
格保持模型的⼀一致性,而不要受到边界之外问题的混淆
每个团队负责自己的模型,并为其他模型提供服务
使用共享内核来管理边界
持续集成


 Con#nuous	
  Integra#on
经过单元测试的代码才能提交到代码库
不要等到所有的功能都完成的时候再去集成,要有时间和频
度规划,否则......
持续集成是根据Bounded Context设计的,不是把系统所有
的组件都进行集成


关于上线那些事儿......
上下文图


       Context	
  Map
Context Map是用来描述全局的
介于项目管理和软件设计之间,属于重叠区域
识别模型,明确作用,定义模型边界的上下文。描述模型与
模型之间的交互方式、上下文之间的交互方式
Money
                   currency
                   amount

                   plus(Money other)
                   minus(Money other)
                   ...




<<Entity>>         <<Root>>             <<Value Object>>
                                                                                    <<Entity>>    <<Root>>
           Order                                    LineItem
                                                                                            Customer
date                                    goods
                                                                                    name
customer                                quantity
                                                                                    surname
amount                                  notes
                                                                                    address
...
                                        subtotal()                                  ...
update()                                ...
                                                                                    updateDiscount()
close()
                                                                                    ...
ship()
...


                                             shipping address
<<Value Object>>

     CustomerData
                                  billing address
name
surname                                                         <<Value Object>>

                                                                          Address
                                             <<Value Object>>   street
                                                                city
                                                                country
                                                                zipcode
衍生关系......
Shared Kernel-Core Domain
团队之间共享部分领域模型
Customer/Supplier
团队之间形成客户与供应商的关系
Conformist-跟随者
严格遵守上游团队的模式
Anti-Corruption Layer(反腐层)
创建⼀一个隔离的层,根据自己的领域模
   型来为客户提供相关的功能
Open Host Service
定义开放协议,提供服务
(Web Service,SOA)
Published Language(公共语言)
 大家都是使用公共语言来交流
      XML,JSON,Restful
领域驱动设计实践
免 纸上 谈兵
D DD,避
改变代码 == 改变模型
建模和编程过程息息相关
分层描述
  名称                           职责
              由于该平台主要面向B/S架构,展示层主要由web资源文件组成,包括
   View       JSP,JS和大量的界面控件,采用了AJAX技术,负责向用户展现丰富的界
              面信息,并执行用户的命令
              负责展示层请求的转发、调度和验证,同时处理后台返回的异常信息,同
 Control      时控制层可以通过Action做远程的请求

              是系统最为丰富的⼀一层,主要负责处理整个系统的业务逻辑。这⼀一层主要
 Domain       包括业务服务和领域模型,同时负责系统的事务管理

              负责数据持久化,支持O/R Mapping和JDBC,对数据源的访问提供多种访
Persistence   问方式

系统的控制层、领域层和持久化层元素都有IOC容器统⼀一管理,实现完全的接口分离和解耦
提炼业务服务
寻找领域模型

‣ 倾听领域专家的语言
‣ 根据领域描述划分业务单元,每个业务服务对应⼀一个业
务单元,覆盖相关的领域对象
‣ 提炼领域对象,定义领域对象之间的关系,找到聚合根
‣ 定义领域对象的属性、行为和边界
‣ 重构和精化
总结
• 成熟、清晰的分层架构
分层架构   • 领域对象与现实世界的业务映射
       • 明确的职责划分



       • 领域对象是核心
 复用    • 领域对象复用:完整的业务对象描述
       • 设计复用:设计基于领域对象而非数据库




       • 具备复杂业务逻辑的软件开发
       • 对设计和开发人员要求较高
使用场景
       • 不适用普通CRUD的业务
       • 软件的维护性和扩展性良好
供应链



DDD解决的主要问题是软件的复杂度
DDD的应用场景是行为中心的软件系统,而
不是数据中心


         微博
命令与查询责任分离模式
 ——Command Query Responsibility Segregation
Event Handlers   读写
Pub/Sub机制          分离
练习
网上书店(Book Store)

‣采用DDD设计思想构建的⼀一个应用系统
‣通过网上书店系统,可以快速理解领域驱动设计
‣该系统实现网上书店的常用功能:包括浏览书籍、挑选书籍、提交订
单、查看订单、自动折扣、处理订单、取消订单等。未登录用户可以浏
览和挑选书籍;已登录用户可以提交和查看自己相关的订单;管理员可
以处理订单
领域对象
‣ Account——账户
‣ Order——订单
‣ Book——书籍
‣ Cart——购物车
‣ Item——订单项
‣ Discount——折扣
构建分层架构
提炼业务服务
寻找领域模型
图形展示
Service
架构永远变迁
优化永无止境
Questions?

        Follow me
        微博:@池建强 | twitter: @sagacity

Weitere ähnliche Inhalte

Ähnlich wie 领域驱动设计实践

An introduce to n hibernate (part 1) pub
An introduce to n hibernate (part 1) pubAn introduce to n hibernate (part 1) pub
An introduce to n hibernate (part 1) pub
jiangxu
 
淘宝开放产品前端实践
淘宝开放产品前端实践淘宝开放产品前端实践
淘宝开放产品前端实践
taobao.com
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renren
d0nn9n
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
hua qiu
 
Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)
ziggear
 
Ecma script edition5-小试
Ecma script edition5-小试Ecma script edition5-小试
Ecma script edition5-小试
lydiafly
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文
Guo Albert
 
Js doc toolkit
Js doc toolkitJs doc toolkit
Js doc toolkit
jay li
 
希望科技研发部变量命名及编码规范
希望科技研发部变量命名及编码规范希望科技研发部变量命名及编码规范
希望科技研发部变量命名及编码规范
Hongjian Wang
 
Lotus domino开发教程
Lotus domino开发教程Lotus domino开发教程
Lotus domino开发教程
dyzm_2000
 
前端本地应用程序网络
前端本地应用程序网络前端本地应用程序网络
前端本地应用程序网络
tblanlan
 

Ähnlich wie 领域驱动设计实践 (20)

An introduce to n hibernate (part 1) pub
An introduce to n hibernate (part 1) pubAn introduce to n hibernate (part 1) pub
An introduce to n hibernate (part 1) pub
 
淘宝开放产品前端实践
淘宝开放产品前端实践淘宝开放产品前端实践
淘宝开放产品前端实践
 
ASP.NET Core 2.1設計新思維與新發展
ASP.NET  Core 2.1設計新思維與新發展ASP.NET  Core 2.1設計新思維與新發展
ASP.NET Core 2.1設計新思維與新發展
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renren
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
 
Hibernate
HibernateHibernate
Hibernate
 
Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)Web设计 3 java_script初探(程序员与设计师的双重眼光)
Web设计 3 java_script初探(程序员与设计师的双重眼光)
 
Ecma script edition5-小试
Ecma script edition5-小试Ecma script edition5-小试
Ecma script edition5-小试
 
Ria lqj
Ria lqjRia lqj
Ria lqj
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文
 
基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理
 
Js doc toolkit
Js doc toolkitJs doc toolkit
Js doc toolkit
 
getPDF.aspx
getPDF.aspxgetPDF.aspx
getPDF.aspx
 
getPDF.aspx
getPDF.aspxgetPDF.aspx
getPDF.aspx
 
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit TestingASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
 
希望科技研发部变量命名及编码规范
希望科技研发部变量命名及编码规范希望科技研发部变量命名及编码规范
希望科技研发部变量命名及编码规范
 
從零開始做架構圖
從零開始做架構圖從零開始做架構圖
從零開始做架構圖
 
Lotus domino开发教程
Lotus domino开发教程Lotus domino开发教程
Lotus domino开发教程
 
前端本地应用程序网络
前端本地应用程序网络前端本地应用程序网络
前端本地应用程序网络
 

领域驱动设计实践