你在使用哪种编程语言?快来投票,亲手选出你心目中的编程语言之王 了解详情
写点什么

DCI:James O. Coplien 和 Trygve Reenskau 提出的新架构方法

2009 年 5 月 14 日

James O. Coplien 和 Trygve Reenskaug 最近发表了系列文章的第一篇,该系列文章介绍一种面向对象编程的新架构方法,该方法基于 DCI(数据、上下文和交互)模式

作者在第一篇文章里主张,即便面向对象编程有助于描述结构,但它并不能充分表明用户的心智模式,因为它不能表示“最终用户的行为需求”。为了说明“行为”到底指什么,他们举了一个储蓄账户对象的例子,该对象可以减少余额,也能提款。按照 Coplien 和 Reenskaug 的意思,“这两种行为完全不同”:“减少余额只是数据的特征:它是什么。提款则反映了数据的目的:它做了什么。”事实上,能减少余额在任何情况下都是以数据为特征的——这一点是不变的。相反,提款则涉及“与 ATM 或审计跟踪之间的交互”——这是动态的,不再关乎“是什么”,而关乎“做什么”。

虽然用户模型很自然地结合了是什么和做什么这两个部分,但“在面向对象里很少有内容会帮助开发人员在代码中描述做什么,在 MVC 里则根本就没有。”“面向对象将这两部分混在一起”,很难把“简单、不变的数据模型和动态的行为模型区分开来”,但从架构和维护的角度来说,把两者分清楚可是很必要的。另外,纯粹的面向对象要求对大型算法进行分割,将各细分部分(也就是方法)分布到对象中,对象与给定的方法有着紧密的联系。即使有些算法能存在于单个对象中,“有意思的业务功能往往还是会跨多个对象。”

James 和 Trygve 提倡用 DCI 模型描述这些动态的行为模型,DCI 模型基于以下三个概念:

——数据,描述领域对象,表示不变的部分;

——交互,以角色的语言去描述,角色是“对象能进行的行为的集合”;

——上下文,可看成是“一个表格,将角色的一个功能(表格的一行)映射到一个对象方法上(表格的列是对象)。表格根据 Context 对象中程序员提供的业务智能进行填充,对给定的用例来说,Context 知道什么对象应该扮演什么角色。”

作者用转账用例给读者做了具体的说明。转账会涉及储蓄账户和投资账户,但用户在讨论这个用例的时候更喜欢用“源账户”和“目的账户”。这全都是角色,而转账的交互可以用角色的算法描述。上下文不同,角色可以由不同的对象去扮演:在这个具体的例子中,源账户角色将关联到储蓄账户对象上。

代码中能表示角色的一般设计概念是Trait,但 Trait 的实现依赖于特定编程语言中存在的结构:Scala 中的 Traits、Squeak Smalltalk 中的 Squeak Traits、C++ 中的模板等……DCI 方法的最大好处是,作者提供的示例代码“几乎就是用例描述文字的自然展开”:

比起让逻辑主观任意地跨越许多类的边界,DCI 将更容易理解——因为更符合最终用户的心智模型中逻辑的自然组织。

这篇文章引发了很多评论和批评,让James 和Trygve 提供更多精确的DCI 概念

Michael Feather 和很多其他评论者认为,把转账的任务指派给源账户太随意了,这实际上并不符合用户的心智模型,在用户看来,转账并不是由哪个账户来完成的,而是由银行或交易对象完成,“交易对象映射到交互的用户概念”。比如说,John Zabroski 建议用分析类 TransferSlip。另一些人则认为,DCI 所涉及的正是人们早已知道的内容:某些语言中的“Traits”,“函数编程的一般思想(算法比较紧要、应该能表达清楚)”,等等……

James O. Coplien 回应道,DCI“试图结合二十世纪八十年代面向对象里很多很好的领域建模概念,重现过程语言(比如 Fortran)过去用算法表达给我们带来的方便性”。像 Scala 这些语言中的 Traits 是一种实现方法,但在其它语言里可以用不同的结构去完成 DCI 架构。实际上,重要的并不是文中建议的工具或使用的例子,而是区分以下内容的架构方法:1)任何情况下都专属于领域对象的行为;2)特定于上下文的行为,这种行为属于业务逻辑,往往跨越多个对象。正如 Bill Venners 所说,“如果应用的十个用例都涉及账户概念,结果可能每个用例都有一些行为进入了 Account 类”,这对设计者来说也是个很大的挑战。所以,运用 DCI 让“对象在每个上下文中有一个不同的类”是“改善 OO 程序可理解性的一种尝试”:

[……] 这篇文章指出,有时候你可能在对象中放置了太多的行为,因为在不同上下文中要用到这些行为的不同子集。作者建议用 Traits 对额外的内容进行建模,Traits 可以映射到用户心智模型的任务上去。然后在某个特定的上下文或用例中,再往基本的领域对象中添加上下文需要的 Traits。

Coplien 指出了 DCI 使代码更易于阅读和调试的四个理由,以强调 DCI 带来的可读性:

  1. 跨业务功能的上下文切换比较少,而且更接近心智模型(基于角色),而不是程序员模型(基于领域);
  2. 包含多态(inclusion polymorphism)几乎完全消失了。调用 Foo 就得到 Foo:而不是子类型化层次中派生出的众多 Foo 里的一个。
  3. 我可以找到有业务价值的测试点:也就是说,我可以做到真正的 BDD(行为驱动开发)。这更易于开发测试用例,以支持调试。
  4. 不太需要进行运行时调试,因为代码在编译时就更加易读。

Trygve Reenskaug 强调说,要理解 DCI,需要“减少对类抽象的关注,勇于接受更适用于以上对象结构的额外抽象”,还需要“增加一种既能扩充类,又仍然保持对象身份的对象抽象”,即角色

查看英文原文: Data, Context and Interaction : A New Architectural Approach by James O. Coplien and Trygve Reenskau

2009 年 5 月 14 日 00:534963
用户头像

发布了 151 篇内容, 共 53.6 次阅读, 收获喜欢 16 次。

关注

评论

发布
暂无评论
发现更多内容

Centos 7 安装RabbitMQ(RPM)

Kevin Liao

RabbitMQ RPM安装

NIO看破也说破(一)—— Linux/IO基础

小眼睛聊技术

Linux 架构 后端 Netty nio

冥想与呼吸法之于情绪控制

树上

情绪 冥想 呼吸法 呼吸 自我

Web3极客日报#135

谢锐 | Frozen

区块链 独立开发者 技术社区 Rebase Web3 Daily

leetcode8. 字符串转换整数 (atoi)

Damien

算法 数学

程序员为什么要提高赚钱能力?程序员如何提高赚钱能力?

陆陆通通

赚钱

第三方支付概述

cf

支付 网联 备付金

排序系列插入/希尔

脚动两轮男之漂流小王子

做一个好产品的初衷:用户值得

池建强

创业 产品 写作

Golang杂谈 - graceful shutdown为何离奇失效?

星语

golang 后端 平滑重启 服务端

Impala UDTF 功能实现

小鹏

大数据 hadoop cloudera 数据仓库

创投机会诞生在这四个核心变量中 | 2019年在某大学课堂做的一次讲演的实录

邓瑞恒Ryan

创业 管理 投资 行业资讯

游戏夜读 | 工具游戏的辉煌

game1night

基准测试神器JMH —— 详解36个官方例子

捉虫大师

Java 性能 JMH

排序系列快排/内省

脚动两轮男之漂流小王子

Java并发编程系列——分布式锁

孙苏勇

Java zookeeper 并发编程 多线程 分布式锁

MySQL自增ID以及其他唯一ID方式分析

Bruce Duan

MySQL自增ID 唯一ID

花更多的时间在自己的优势上

Neco.W

创业 自我管理 重新理解创业

为什么厉害的人精力都那么好?

非著名程序员

程序员 程序人生 提升认知 精力管理

leetcode141. 环形链表

Damien

算法 链表 LeetCode

排序系列归并/timsort

脚动两轮男之漂流小王子

五十年前的一桩公案:数据库关系模型的流行史(下)

青菜年糕汤

数据库 分布式数据库 数据库规范 关系型数据库 数据库设计

Web3极客日报#134

谢锐 | Frozen

区块链 独立开发者 技术社区 Rebase Web3 Daily

笔记:《如何系统思考》之因果回路图

wiflish

思维方式

人人都要有经营意识

Neco.W

创业 重新理解创业 公司管理

第一次手动编译openjdk11

py ploughman

jdk

Centos 7 使用Firewalld

Kevin Liao

Centos 7 防火墙 Firewalld防火墙 Firewalld

Java并发编程基础--线程

Java收录阁

Java 线程

程序员陪娃漫画系列——当她想吃的时候

孙苏勇

程序员 生活 程序员人生 陪伴 漫画

Redis学习笔记(安装)

编程随想曲

redis

排序系列之选择/冒泡

脚动两轮男之漂流小王子

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

DCI:James O. Coplien和Trygve Reenskau提出的新架构方法-InfoQ