程序设计

Hessian 协议解释与实战(五):对象与映射

Hessian 协议解释与实战(五):对象与映射

D瓜哥
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 在上一篇文章 Hessian 协议解释与实战(四):数组与集合 中研究了数组和集合的处理方式。接下来介绍对象和映射的处理。 基础工具方法 基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):基础工具方法 中提到的几个方法。 另外,在 Hessian 协议解释与实战(四):数组与集合 中,又对一些方法做了扩展和更新。 下面,我们来看一看映射的处理。 映射 坦白讲,个人觉得 Hessian 2.0 序列化协议(中文版):映射 的协议定义写的非常模糊。倒是给的示例,还可圈可点。 相关代码实现 通过 Hessian 源码分析(Java) 可以指定, MapSerializer 是处理映射的 Serializer。所以,只需要关注一下 MapSerializer 就可以对映射的处理一目了然。结合代码,可以看出,映射的序列化流程大致如下:
Hessian 协议解释与实战(四):数组与集合

Hessian 协议解释与实战(四):数组与集合

D瓜哥
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 在上一篇文章 Hessian 源码分析(Java) 对 Hessian 的 Java 实现做了一个概要的分析,对处理流程以及整体架构做了一个简单的分析。接下来,回到主题,继续来解释 Hessian 序列化协议。这篇文章,我们来重点分析一下数组与集合相关的操作。 基础工具方法 基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):基础工具方法 中提到的几个方法。 对打印字符的工具做一下改造: /** * 打印字节数组 * * @author D瓜哥 · https://www.diguage.com/ */ private void printBytes(byte[] result) { if (Objects.
Hessian 源码分析(Java)

Hessian 源码分析(Java)

D瓜哥
前面通过几篇文章,解释并实践了一下 Hessian 的序列化协议。文章目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 该系列第四篇文章准备详细介绍一下 Hessian 对对象、链表以及 Map 等处理。但是,越调试代码,越发觉得应该先对 Hessian 的实现做一个源码分析。于是,就有了本文。 这里有几点需要声明一下: 在上面“解释与实战”系列文章中提到的代码就不再重复说明。 通过“解释与实战”系列文章,大家应该可以领略到,处理序列化有大量的细节。但是,本文并不打算涉及。本文重点是介绍 Hessian 的 Java 实现的架构蓝图。相当于给指明一条路,沿着这条路,大家就可以探索 Hessian 的各种细节。 本文的介绍,全部基于 Hessian 4.0.60 的源码。由于没有找到 Hessian 的仓库,D瓜哥从 Hessian 的网站下,下载了源码包,解压后发布在了 GitHub 上: Hessian — The source code of Hessian Library.。 主要流程 作为一个序列化框架,最主要的功能就是序列化和反序列化。所以,这两个流程至关重要。 序列化流程 在“解释与实战”系列文章,都是通过调用 Hessian2Output 类中的各种 write 方法来完成实验的。在研究针对对象的序列化时,通过调试 Hessian2Output.
Hessian 协议解释与实战(三):字符串

Hessian 协议解释与实战(三):字符串

D瓜哥
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 在上一篇文章 Hessian 协议解释与实战(二):长整型、二进制数据与 Null 中研究了长整型、二进制数据与 null 等三种数据类型的处理方式。接下来,我们再来介绍字符串的处理情况。 基础工具方法 基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):布尔、日期、浮点数与整数:基础工具方法 中提到的几个方法。 字符串 在 Hessian 2.0 序列化协议(中文版):字符串类型数据 中对字符串类型的数据做了描述。总得来说,还算比较清楚。但是一些细节不是特别清楚,比如“以 UTF-8 编码的 16 位 Unicode 字符串”,再比如,四个字节的 UTF-8 怎么被 16 位 Unicode 字符串表示等。这里深究一下。
Hessian 协议解释与实战(二):长整型、二进制数据与 Null

Hessian 协议解释与实战(二):长整型、二进制数据与 Null

D瓜哥
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 在上一篇文章 Hessian 协议解释与实战(一) 中研究了布尔型数据、日期类型、浮点类型数据、整数类型数据等四种数据类型的处理方式。接下来,我们再来介绍长整数类型数据、二进制数据和 null 的处理情况。 基础工具方法 基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):布尔、日期、浮点数与整数:基础工具方法 中提到的几个方法。 长整数类型数据 在 Hessian 2.0 序列化协议(中文版):长整数类型数据 中对长整型类型的数据做了描述,处理思路与整型数据类型的处理非常类似。所以,对长整型数据的验证思路也与 Hessian 协议解释与实战(一):整数类型数据 类似,在分割点进行实验和验证。 /** * @author D瓜哥 · https://www.diguage.com/ */ @Test public void testLong() throws Throwable { // 演示各个“区间”的分界线 longTo(Long.
Hessian 协议解释与实战(一):布尔、日期、浮点数与整数

Hessian 协议解释与实战(一):布尔、日期、浮点数与整数

D瓜哥
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。 目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 基础工具方法 Hessian 序列化之后的数据,都是字节数组,为了方便查看字节数组的二进制形式和十六进制形式,在正式开始之前,先介绍一下期间用到的辅助工具方法。闲言少叙,直接上代码: /** * 创建 Hessian2Output 对象,以便用于序列化 * * @author D瓜哥 · https://www.diguage.com/ */ private Hessian2Output getHessian2Output(OutputStream stream) { SerializerFactory serializerFactory = new SerializerFactory(); serializerFactory.setAllowNonSerializable(true); Hessian2Output result = new Hessian2Output(stream); result.
Hessian 2.0 序列化协议(中文版)

Hessian 2.0 序列化协议(中文版)

D瓜哥
公司在微服务系统中,序列化协议大多数使用 MessagePack。但是,由于 MessagePack 设计限制,导致微服务接口在增减参数时,只能在最后操作。但是,由于个人操作,难免失误,结果造成因为增减字段导致的事故层出不穷。最近,一些条件成熟,准备推动部门将序列化协议切换到 Hessian。 原以为,切换到 Hessian 就可以万事大吉。但是,在和同事的沟通中发现,同事反馈,Hessian 本身也有一些限制。为了对 Hessian 有一个更深入的了解,干脆就把 Hessian 序列化协议读一遍。看协议,文字不多,干脆就把协议完整翻译一遍。闲言少叙,正文开始。 Hessian 2.0 序列化协议 协议解释 针对该协议有很多言语不详,甚至模糊不清之处,专门做了一些解释和实践,叙述系列文章,用于辅助消化理解。目录如下: Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。 Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。 Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。 Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。 Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。 Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。 未完待续,敬请继续关注 "地瓜哥"博客网。 1. 简介 Hessian 是一种设计用于面向对象传输的,动态类型的,二进制序列化 Web 服务协议。 2. 设计目标 Hessian 是动态类型的,紧凑,跨语言的。 Hessian 协议有如下设计目标: 它必须自我描述序列化类型,即不需要外部架构或接口定义。 它必须是语言独立的,同时支持脚本语言。 它必须一次性读取或者写入。 它必须尽可能紧凑。 它必须简单,以便可以有效地测试和实施。 它必须尽可能快。 它必须支持 Unicode 字符串。
在 Spring Boot 中 Jackson 日期格式化技巧

在 Spring Boot 中 Jackson 日期格式化技巧

D瓜哥
使用 Spring Boot 时,需要使用 Jackson 处理一些 Java Time API 类型的 JSON 序列化问题,在处理一些类的字段时,可以通过直接在属性上加注解的方式来指定其格式化样式。但是,昨天同事遇到一个格式化 Map 数据的问题,这样就不能通过加注解来解决格式化样式的问题了。 在网上各种搜索,各种尝试后,终于解决了这个问题,记录一下,以备不时之需。 闲言少叙,直接上代码: package com.diguage.demo.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.util.StdDateFormat; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import static com.fasterxml.jackson.databind.SerializationFeature.*; import static java.time.format.DateTimeFormatter.ofPattern; / * 配置类 * * @author D瓜哥 · https://www.diguage.com */ @Configuration public class Config { / * 创建 ObjectMapper 对象,配置日期格式化 * * @author D瓜哥 · https://www.
《领域驱动设计》读书笔记(三):通过重构来加深理解

《领域驱动设计》读书笔记(三):通过重构来加深理解

我们面临的真正挑战是找到深层次的模型,这个模型不但能够捕捉到领域专家的微妙的关注点,还可驱动切实可行的设计。我们的最终目的是开发出能够捕捉到领域深层含义的模型。 要想成功地开发出实用的模型,需要注意以下 3 点: 复杂巧妙的领域模型是可以实现的,也是值得我们去花费力气实现的。 这样的模型离开不断的重构是很难开发出来的,重构需要领域专家和热爱学习领域知识的开发人员密切参与进来。 要实现并有效地运用模型,需要精通设计技巧。 重构就是在不改变软件功能的前提下重新设计它。 自动化的单元测试套件能够保证对代码进行相对安全的试验。 设计模式重构 — 为实现更深层模型而进行的重构。 代码细节重构 简称为“领域模型重构”。 学习以更高维度去看待问题。 《重构》一书中所列出的重构分类涵盖了大部分常用的代码细节重构。这些重构主要是为了解决一些可以从代码中观察到的问题。 领域模型会随着新认识的出现而不断变化,由于其变化如此多样,以至于根本无法整理出一个完整的目录。 建模和设计都需要你发挥创造力。 对象分析的传统方法是先在需求文档中确定名词和动词,并将其作为系统的初始对象和方法。 事实上,初始模型通常都是基于对领域的浅显认知而构建的,既不够成熟也不够深入。 深层模型能够穿过领域表象,清楚地表达出领域专家们的主要关注点以及最相关的知识。 戴久了的手套在手指关节处会变得柔软;而其他部分则依然硬实,可起到保护的作用。 柔性设计除了便于修改,还有助于改进模型本身。 Model-Driven Design 需要以下两个方面的支持:深层模型使设计更具表现力;同时,当设计的灵活性可以让开发人员进行试验,而设计又能清晰地表达出领域含义时,那么这个设计实际上就能够将开发人员的深层理解反馈到整个模型发现的过程中。 由于模型和设计之间具有紧密的关系,因此如果代码难于重构,建模过程也会停滞不前。 你需要富有创造力,不断地尝试,不断地发现问题才能找到合适的方法为你所发现的领域概念建模,但有时你也可以借用别人已建好的模式。 第 8 章 突破 Figure 1. 重构/突破 小改进可防止系统退化,成为避免模型变得陈腐的第一道防线。 重构的原则是始终小步前进,始终保持系统正常运转。 过渡到真正的深层模型需要从根本上调整思路,并且对设计做大幅修改。 不要试图去制造突破,那只会使项目陷入困境。通常,只有在实现了许多适度的重构后才有可能出现突破。 要为突破做好准备,应专注于知识消化过程,同时也要逐渐建立健壮的 Ubiquitous Language 。 第 9 章 将隐式概念转变为显式概念 深层建模的第一步就是要设法在模型中表达出领域的基本概念。 若开发人员识别出设计中隐含的某个概念或是在讨论中受到启发而发现一个概念时,就会对领域模型和相应的代码进行许多转换,在模型中加入一个或多个对象或关系,从而将此概念显式地表达出来。 概念挖掘 倾听领域专家使用的语言。有没有一些术语能够简洁地表达出复杂的概念?他们有没有纠正过你的用词(也许是很委婉的提醒)?当你使用某个特定词语时,他们脸上是否已经不再流露出迷惑的表情?这些都暗示了某个概念也许可以改进模型。 有些概念可能需要你自己去挖掘和创造。要挖掘的地方就是设计中最不足的地方,也就是操作复杂且难于解释的地方。 看书与咨询领域专家并不冲突。即便能够从领域专家那里得到充分的支持,花点时间从文献资料中大致了解领域理论也是值得的。 开发人员还有另一个选择,就是阅读在此领域中有过开发经验的软件专业人员编写的资料。 阅读书籍并不能提供现成的解决方案,但可以为她提供一些全新的实验起点,以及在这个领域中探索过的人总结出来的经验。 如何为那些不太明显的概念建模 显式的约束 约束是模型概念中非常重要的类别。它们通常是隐含的,将它们显式地表现出来可以极大地提高设计质量。 将约束条件提取到其自己的方法中,这样就可以通过方法名来表达约束的含义,从而在设计中显式地表现出这条约束。 下面是一些警告信号,表明约束的存在正在扰乱其“宿主对象”(Host Object)的设计: 计算约束所需的数据从定义上看并不属于这个对象。 相关规则在多个对象中出现,造成了代码重复或导致不属于同一族的对象之间产生了继承关系。 很多设计和需求讨论是围绕这些约束进行的,而在代码实现中,它们却隐藏在过程代码中。 如果约束的存在掩盖了对象的基本职责,或者如果约束在领域中非常突出但在模型中却不明显,那么就可以将其提取到一个显式的对象中,甚至可以把它建模为一个对象和关系的集合。 将过程建模为领域对象 对象是用来封装过程的,这样我们只需考虑对象的业务目的或意图就可以了。 过程是应该被显式表达出来,还是应该被隐藏起来呢?区分的方法很简单:它是经常被领域专家提起呢,还是仅仅被当作计算机程序机制的一部分? 模式:Specification 业务规则通常不适合作为 Entity 或 Value Object 的职责,而且规则的变化和组合也会掩盖领域对象的基本含义。但是将规则移出领域层的结果会更糟糕,因为这样一来,领域代码就不再表达模型了。
《领域驱动设计》读书笔记(二):模型驱动设计的构造块

《领域驱动设计》读书笔记(二):模型驱动设计的构造块

遵循“职责驱动设计”的原则, “契约式设计”思想。 开发一个好的领域模型是一门艺术。 Figure 1. 模型驱动设计语言 第 4 章 分离领域 模式:Layered Architecture 在面向对象的程序中,常常会在业务对象中直接写入用户界面、数据库访问等支持代码。而一些业务逻辑则会被嵌入到用户界面组件和数据库脚本中。这么做是为了以最简单的方式在短期内完成开发工作。 如果与领域有关的代码分散在大量的其他代码之中,那么查看和分析领域代码就会变得异常困难。对用户界面的简单修改实际上很可能会改变业务逻辑,而要想调整业务规则也很可能需要对用户界面代码、数据库操作代码或者其他的程序元素进行仔细的筛查。这样就不太可能实现一致的、模型驱动的对象了,同时也会给自动化测试带来困难。考虑到程序中各个活动所涉及的大量逻辑和技术,程序本身必须简单明了,否则就会让人无法理解。 要想创建出能够处理复杂任务的程序,需要做到关注点分离——使设计中的每个部分都得到单独的关注。 Layered Architecture 的基本原则是层中的任何元素都仅依赖于本层的其他元素或其下层的元素。 Figure 2. 应用分层 给复杂的应用程序划分层次。在每一层内分别进行设计,使其具有内聚性并且只依赖于它的下层。采用标准的架构模式,只与上层进行松散的耦合。将所有与领域模型相关的代码放在一个层中,并把它与用户界面层、应用层以及基础设施层的代码分开。领域对象应该将重点放在如何表达领域模型上,而不需要考虑自己的显示和存储问题,也无需管理应用任务等内容。这使得模型的含义足够丰富,结构足够清晰,可以捕捉到基本的业务知识,并有效地使用这些知识。 关注点的清晰分离可以使每一层的设计更易理解和维护。 在连接各层的同时不影响分离带来的好处,这是很多模式的目的所在。 各层之间是松散连接的,层与层的依赖关系只能是单向的。上层可以直接使用或操作下层元素,方法是通过调用下层元素的公共接口,保持对下层元素的引用(至少是暂时的),以及采用常规的交互手段。 如果下层元素需要与上层元素进行通信(不只是回应直接查询),则需要采用另一种通信机制,使用架构模式来连接上下层,如回调模式或 Observers 模式。 最早将用户界面层与应用层和领域层相连的模式是 Model-View-Controller(MVC,模型—视图—控制器)框架。 只要连接方式能够维持领域层的独立性,保证在设计领域对象时不需要同时考虑可能与其交互的用户界面,那么这些连接方式就都是可用的。 最好的架构框架既能解决复杂技术问题,也能让领域开发人员集中精力去表达模型,而不考虑其他问题。 不妄求万全之策,只要有选择性地运用框架来解决难点问题,就可以避开框架的很多不足之处。 领域层是模型的精髓 “领域层”则是领域模型以及所有与其直接相关的设计元素的表现,它由业务逻辑的设计和实现组成。 如果领域逻辑与程序中的其他关注点混在一起,就不可能实现这种一致性。将领域实现独立出来是领域驱动设计的前提。 模式:The Smart UI“反模式” Smart UI是另一种设计方法,与领域驱动设计方法迥然不同且互不兼容。 如果一个经验并不丰富的项目团队要完成一个简单的项目,却决定使用 Model-Driven Design 以及 Layered Architecture,那么这个项目组将会经历一个艰难的学习过程。团队成员不得不去掌握复杂的新技术,艰难地学习对象建模。(即使有这本书的帮助,这也依然是一个具有挑战性的任务!)对基础设施和各层的管理工作使得原本简单的任务却要花费很长的时间来完成。简单项目的开发周期较短,期望值也不是很高。所以,早在项目团队完成任务之前,该项目就会被取消,更谈不上去论证有关这种方法的许多种令人激动的可行性了。 即使项目有更充裕的时间,如果没有专家的帮助,团队成员也不太可能掌握这些技术。最后,假如他们确实能够克服这些困难,恐怕也只会开发出一套简单的系统。因为这个项目本来就不需要丰富的功能。 在用户界面中实现所有的业务逻辑。将应用程序分成小的功能模块,分别将它们实现成用户界面,并在其中嵌入业务规则。用关系数据库作为共享的数据存储库。使用自动化程度最高的用户界面创建工具和可用的可视化编程工具。 如果一个架构能够把那些与领域相关的代码隔离出来,得到一个内聚的领域设计,同时又使领域与系统其他部分保持松散耦合,那么这种架构也许可以支持领域驱动设计。 如何让一个有效的领域模型和一个富有表达力的实现同时演进。 第 5 章 软件中所表示的模型 一个对象是用来表示某种具有连续性和标识的事物的呢(可以跟踪它所经历的不同状态,甚至可以跨不同的实现跟踪它),还是用于描述某种状态的属性呢?这是 Entity 与 Value Object 之间的根本区别。 领域中还有一些方面适合用动作或操作来表示,这比用对象表示更加清楚。这些方面最好用 Service 来表示,而不应把操作的责任强加到 Entity 或 Value Object 上,尽管这样做稍微违背了面向对象的建模传统。 Service 是应客户端请求来完成某事。