Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

领域驱动设计实践

6,782 views

Published on

相对全面的领域驱动设计分享,包括设计元素,生命周期,模式,策略和实践经验,同时包含相关的案例阐述。

  • Be the first to comment

领域驱动设计实践

  1. 1. 领域驱动设计实践 @ 瑞友科技IT应用研究院池建强 Twitter: @sagacity Weibo: @池建强 Mail: jackychi@gmail.com
  2. 2. About ME• 池建强,70后程序员,98年毕业,先后就职于洪恩软件、 RocketSofeware和用友集团-瑞友科技,现任瑞友科技IT应用 研究院副院长• 先后从事互联网和企业应用开发,目前致力于基础应用平台 的研究• 热爱技术和编码工作,坚持年轻时的理想,倒霉的乐观者• 技术领域:Java、Python、Ruby、Objective-C、DDD、 OSGi、App Platform
  3. 3. 模型是抽象的 现实是形象的 技巧是重要的 思想是永恒的Domain  Model  -­‐  What  Why  How?
  4. 4. 从软件系统诞生之初,程序设计者就开始梦想有⼀一天能够像建造桥梁和房屋那样“透明”的构造软件,让现实和代码对应起来
  5. 5. 软件开发总是比任何人估计的慢,如果不是有意的放宽项目期限,几乎不会出现提前完成的软件项目和产品。有时候我们必须耐下心来把所有琐碎的、困难的、细节的问题都解决并不断打磨,才能完成,有时候没有别的办法,只能等待
  6. 6. ⼀一个案例
  7. 7. 2010-01 2010-03 2010-05 ...... 2010-12 采用领域驱动的 方式开发 幸福的时光总是短暂的......
  8. 8. 2010-01 2010-03 2010-05 ...... 2010-12 采用领域驱动的 商务要求尽快出⼀一 方式开发 个版本2010-01 2010-03 2010-05 ...... 2011-04 好日子结束了 苦逼的总是开发者
  9. 9. 领域驱动设计不是用来解决开发速度的领域驱动设计是用来解决软件核心复杂性的
  10. 10. 面向对象的分析设计软件系统面向对象的设计思想可谓历史悠久,20世纪70年代的Smalltalk可以说是面向对象语言的经典,直到今天我们依然将这门语言视为面向对象语言的基础面 向 对 象 是 大 部 分 语 言 的 ⼀一 个 基 本 特 性 , 像C++、Java、Objective-C这样的静态语言,Ruby、Python这样的动态语言都是面向对象的语言
  11. 11. 2004年著名建模专家Eric Evans发表了他最具影响力的书籍《Domain-Driven Design》 ——Tackling Complexity in the Heart of Software中文译名:领域驱动设计—软件核心复杂性应对之道,书中提出了“领域驱动设计(简称 DDD)”的概念。
  12. 12. 领域驱动设计事实上针对是OOAD的⼀一个扩展和延伸,DDD基于面向对象分析与设计技术,对技术框架进行了分层规划,同时对每个类进行了策略和类型的划分
  13. 13. 采用DDD的设计思想,业务逻辑不再集中在几个大型的类上,而是由大量相对小的领域对象(类)组成,这些类具备自己的状态和行为,每个类是相对完整的独立体,并与现实领域的业务对象映射。领域模型就是由这样许多的细粒度的类组成
  14. 14. 领域驱动设计是技术人员和领域专家沟通的桥梁技术人员和领域专家沟通的桥梁是领域驱动设计 技术人员 领域驱动设计 沟通 领域专家 桥梁
  15. 15. public  interface  IBookService  { û        double  submitOrder(int  orderId);} 不容易理解的抽象public  interface  IBookService  {        double  submitOrder(Order  order);} ü
  16. 16. 抽象 - 打折策略
  17. 17. 领域模型和事务脚本
  18. 18. 事务脚本(Transaction Script)的核心是过程,每个过程处理来自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql语句来实现数据库信息的处理
  19. 19. 事务脚本(Transaction Script)的核心是过程,每个过程处理来自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql语句来实现数据库信息的处理事务脚本把业务逻辑组织成单个过程,在过程中直接调用数据库,业务逻辑在服务(Service)层处理
  20. 20. Action处理UI层的动作请求,将Request中的数据组装后传递给BusinessService,BS层做简单的逻辑处理后,调用数据访问对象进行数据持久化,其中VO充当了数据传输对象的作用,只具备getter和setter方法,没有状态和行为 Transaction Script
  21. 21. 效果?后果?看代码
  22. 22. 事务脚本模式的特点是简单容易理解,面向过程设计。
  23. 23. 事务脚本模式的特点是简单容易理解,面向过程设计。 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良好,容易理解,而且⼀一个事务的处理不会影响其他事务。
  24. 24. 事务脚本模式的特点是简单容易理解,面向过程设计。 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良好,容易理解,而且⼀一个事务的处理不会影响其他事务。 不过缺点也很明显,对于复杂的业务逻辑处理力不从心,难以保持良好的设计,事务之间的冗余代码不断增多,通过复制粘贴方式进行复用。可维护性和扩展性变差。
  25. 25. Smart UI-反模式 ——在用户界面中实现大部分业务逻辑
  26. 26. 领域模型(Domain Model)‣面向对象分析和设计‣领域模型具备自己的属性行为状态,并与现实世界的业务对象相映射‣各类具备明确的职责划分,领域对象元素之间通过聚合和引用等关系配合解决实际业务应用和规则‣可复用,可维护,易扩展‣可以采用合适的设计模型进行详细设计‣要求设计人员有良好的抽象能力
  27. 27. Domain Model
  28. 28. 我们也来看代码
  29. 29. 在实际的设计中,我们需要根据具体的需求选择相应的设计模式。具备复杂业务逻辑的核心业务系统适合使用领域模型,简单的信息管理系统或大数据处理可以考虑采用事务脚本模式
  30. 30. 领域驱动设计元素
  31. 31. • 成熟、清晰的分层架构分层架构 • 领域对象与现实世界的业务映射 • 明确的职责划分 • 领域对象是核心 复用 • 领域对象复用:完整的业务对象描述 • 设计复用:设计基于领域对象而非数据库 • 具备复杂业务逻辑的软件开发 • 对设计和开发人员要求较高使用场景 • 不适用普通CRUD的业务 • 软件的维护性和扩展性良好
  32. 32. 分层架构
  33. 33. 名称 职责 展现层 负责向用户展现信息以及解释用户命令 很薄的⼀一层,用来协调应用的活动。它不包含业务逻辑。它不保留 应用层 业务对象的状态,但它保有应用任务的进度状态 本层包含关于领域的信息。这是业务软件的核心所在。在这里保留 领域层 业务对象的状态,对业务对象和它们状态的持久化被委托给了基础 设施层。 本层作为其他层的支撑库存在。它提供了层间的通信,实现对业务基础设施层 对象的持久化,包含对用户界面层的支撑库等作用
  34. 34. 实体,值对象,服务
  35. 35. En#ty(实体)—  人/座位-­‐先到先得?
  36. 36. Value  Object(值对象)—画笔/地址
  37. 37. name *
  38. 38. Services(服务)
  39. 39. Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象
  40. 40. Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时对象,可以用来传递参数或作为实体的属性,也可以封装复杂的计算逻辑
  41. 41. Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时对象,可以用来传递参数或作为实体的属性,也可以封装复杂的计算逻辑Services:为上层建筑提供可操作的接口,负责对领域对象进行调度和封装,同时可以对外提供各种形式的服务
  42. 42. 领域模型的生命周期
  43. 43. 关系数据库 面向对象数据库 NoSql 创建 存储修改 活动状态 数据库 重建 删除 归档 数据库或文件 删除
  44. 44. Factory和Repository基于Aggregate,对特定生命周期转换的复杂性进行了封装
  45. 45. Aggregate(聚合)
  46. 46. 什么是聚合,我们来画⼀一下
  47. 47. Item Product<<IPaymentStrategy>> CashPay CreditCardPay Aggregate  root
  48. 48. Factory  -­‐  IoC
  49. 49. <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();
  50. 50. Repository
  51. 51. ‣ 操作持久对象并管理其生命周期‣ 领域对象和持久化解藕‣ 封装持久化技术 ‣ 多数据源、连接池、数据源访问代理 ‣ O/R Mapping技术 ‣ NoSql ‣ 分布式文件系统‣ 持久化层可替换
  52. 52. 来自QCon淘宝的分享
  53. 53. 规则引擎的案例
  54. 54. 领域元素‣ Package——规则包‣ Rule——规则‣ Attribute——规则属性‣ When/Then——条件‣ ......
  55. 55. 如何实现这样⼀一个设计呢? 看例子吧
  56. 56. ⼀一些原则
  57. 57. 表意接口Inten#on  Revealing  Interface
  58. 58. 如果⼀一个开发人员为了使用⼀一个组件必须要去研究 它的实现,那么就失去了封装的意义
  59. 59. 无副作用函数 Side-­‐Effect-­‐Free  Func#on
  60. 60. 所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果——函数式编程?
  61. 61. 所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果——函数式编程?利用VO的不变性,创建无副作用的函数,例如,传入或返回的对象是by value,而不是by reference,对返回值的修改,不会影响原来的对象。
  62. 62. Conceptual Contour 概念轮廓
  63. 63. 通过坝或其他手段把⼀一个湖分割为几块,在任何⼀一块中投入石子都不会影响其他部分。把设计元素(行为、接口、类、聚合等)分解为内聚单元。通过重构,找出模型中经常变化的部分和基本稳定的部分。
  64. 64. 如何实现组件之间的解耦
  65. 65. ESB也是⼀一种方式,但是远程调用?事务? 设计时需要慎重选择
  66. 66. 小结⼀一表意接口把对象描述成有意义的单元。无副作用函数让我们可以安全的使用这些单元。概念轮廓让这些单元更稳定,更符合直觉,更容易组合
  67. 67. 小结二低耦合是对象设计的⼀一个基本要素,尽可能保持低耦合。把其他所有无关的概念提取到对象之外。消除所有不重要的依赖。限制交叉依赖的方法: 1、子系统 2、模块化 3、聚合 4、单向关联
  68. 68. 领域模式
  69. 69. Specifica#ons
  70. 70. ‣ 规约是⼀一种布尔断言‣ 规约是业务规则的⼀一部分‣ 理论上规约类中的方法只有⼀一个:IsSatisifedBy( Object )‣ 规约用来测试对象是否满足某种条件,用来进行对象查询,也可以作为某个对象的创建条件‣ 单⼀一规约规则。多个规约通过组合表现复杂的规约
  71. 71. 增加规约:public class BookShelf { 1、不同作者的书放到相应 private List books; 的书架 2、不同类型的书放到相应 public BookShelf(){ 的书架 books = new ArrayList(); } public void addBook( Book book ){ books.add(book); }}
  72. 72. 引入规约 <<Specification>>
  73. 73. public class AuthorSpecification implementsSpecification { 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) );}
  74. 74. 边界上下文 Bounded  Context
  75. 75. 明确的定义模型所应用的上下文。根据团队的组织、软件系统的功能和物理表现(代码数据库)来设置模型的边界。在这些边界中严格保持模型的⼀一致性,而不要受到边界之外问题的混淆每个团队负责自己的模型,并为其他模型提供服务
  76. 76. 使用共享内核来管理边界
  77. 77. 持续集成 Con#nuous  Integra#on
  78. 78. 经过单元测试的代码才能提交到代码库不要等到所有的功能都完成的时候再去集成,要有时间和频度规划,否则......持续集成是根据Bounded Context设计的,不是把系统所有的组件都进行集成关于上线那些事儿......
  79. 79. 上下文图 Context  Map
  80. 80. Context Map是用来描述全局的介于项目管理和软件设计之间,属于重叠区域识别模型,明确作用,定义模型边界的上下文。描述模型与模型之间的交互方式、上下文之间的交互方式
  81. 81. Money currency amount plus(Money other) minus(Money other) ...<<Entity>> <<Root>> <<Value Object>> <<Entity>> <<Root>> Order LineItem Customerdate goods namecustomer quantity surnameamount notes address... subtotal() ...update() ... updateDiscount()close() ...ship()... shipping address<<Value Object>> CustomerData billing addressnamesurname <<Value Object>> Address <<Value Object>> street city country zipcode
  82. 82. 衍生关系......
  83. 83. Shared Kernel-Core Domain团队之间共享部分领域模型
  84. 84. Customer/Supplier团队之间形成客户与供应商的关系
  85. 85. Conformist-跟随者严格遵守上游团队的模式
  86. 86. Anti-Corruption Layer(反腐层)创建⼀一个隔离的层,根据自己的领域模 型来为客户提供相关的功能
  87. 87. Open Host Service定义开放协议,提供服务(Web Service,SOA)
  88. 88. Published Language(公共语言) 大家都是使用公共语言来交流 XML,JSON,Restful
  89. 89. 领域驱动设计实践
  90. 90. 免 纸上 谈兵D DD,避
  91. 91. 改变代码 == 改变模型建模和编程过程息息相关
  92. 92. 分层描述 名称 职责 由于该平台主要面向B/S架构,展示层主要由web资源文件组成,包括 View JSP,JS和大量的界面控件,采用了AJAX技术,负责向用户展现丰富的界 面信息,并执行用户的命令 负责展示层请求的转发、调度和验证,同时处理后台返回的异常信息,同 Control 时控制层可以通过Action做远程的请求 是系统最为丰富的⼀一层,主要负责处理整个系统的业务逻辑。这⼀一层主要 Domain 包括业务服务和领域模型,同时负责系统的事务管理 负责数据持久化,支持O/R Mapping和JDBC,对数据源的访问提供多种访Persistence 问方式系统的控制层、领域层和持久化层元素都有IOC容器统⼀一管理,实现完全的接口分离和解耦
  93. 93. 提炼业务服务
  94. 94. 寻找领域模型‣ 倾听领域专家的语言‣ 根据领域描述划分业务单元,每个业务服务对应⼀一个业务单元,覆盖相关的领域对象‣ 提炼领域对象,定义领域对象之间的关系,找到聚合根‣ 定义领域对象的属性、行为和边界‣ 重构和精化
  95. 95. 总结
  96. 96. • 成熟、清晰的分层架构分层架构 • 领域对象与现实世界的业务映射 • 明确的职责划分 • 领域对象是核心 复用 • 领域对象复用:完整的业务对象描述 • 设计复用:设计基于领域对象而非数据库 • 具备复杂业务逻辑的软件开发 • 对设计和开发人员要求较高使用场景 • 不适用普通CRUD的业务 • 软件的维护性和扩展性良好
  97. 97. 供应链DDD解决的主要问题是软件的复杂度DDD的应用场景是行为中心的软件系统,而不是数据中心 微博
  98. 98. 命令与查询责任分离模式 ——Command Query Responsibility Segregation
  99. 99. Event Handlers 读写Pub/Sub机制 分离
  100. 100. 练习
  101. 101. 网上书店(Book Store)‣采用DDD设计思想构建的⼀一个应用系统‣通过网上书店系统,可以快速理解领域驱动设计‣该系统实现网上书店的常用功能:包括浏览书籍、挑选书籍、提交订单、查看订单、自动折扣、处理订单、取消订单等。未登录用户可以浏览和挑选书籍;已登录用户可以提交和查看自己相关的订单;管理员可以处理订单
  102. 102. 领域对象‣ Account——账户‣ Order——订单‣ Book——书籍‣ Cart——购物车‣ Item——订单项‣ Discount——折扣
  103. 103. 构建分层架构提炼业务服务寻找领域模型图形展示
  104. 104. Service
  105. 105. 架构永远变迁优化永无止境
  106. 106. Questions? Follow me 微博:@池建强 | twitter: @sagacity

×