在上一讲中,我们讨论了如何了解一个软件的设计,主要是从三个部分入手:模型、接口和实现。那么,在接下来的三讲中,我将结合几个典型的开源项目,告诉你如何具体地理解一个软件的模型、接口和实现。
今天这一讲,我们就先来谈谈了解设计的第一步:模型。如果拿到一个项目,我们怎么去理解它的模型呢?
我们肯定要先知道项目提供了哪些模型,模型又提供了怎样的能力。这是所有人都知道的事情,我并不准备深入地去探讨。但如果只知道这些,你只是在了解别人设计的结果,这种程度并不足以支撑你后期对模型的维护。
在一个项目中,常常会出现新人随意向模型中添加内容,修改实现,让模型变得难以维护的情况。造成这一现象的原因就在于他们对于模型的理解不到位。
我们都知道,任何模型都是为了解决问题而生的,所以,理解一个模型,需要了解在没有这个模型之前,问题是如何被解决的,这样,你才能知道新的模型究竟提供了怎样的提升。也就是说,理解一个模型的关键在于,要了解这个模型设计的来龙去脉,知道它是如何解决相应的问题。
今天我们以 Spring 的 DI 容器为例,来看看怎样理解软件的模型。
耦合的依赖
Spring 在 Java 世界里绝对是大名鼎鼎,如果你今天在做 Java 开发而不用 Spring,那么你大概率会被认为是个另类。
今天很多程序员都把 Spring 当成一个成熟的框架,很少去仔细分析 Spring 的设计。但作为一个从 0.8 版本就开始接触 Spring 的程序员,我刚好有幸经历了 Spring 从渺小到壮大的过程,得以体会到 Spring 给行业带来的巨大思维转变。
如果说 Spring 这棵参天大树有一个稳健的根基,那其根基就应该是 Spring 的 DI 容器。DI 是 Dependency Injection 的缩写,也就是“依赖注入”。Spring 的各个项目都是这个根基上长出的枝芽。
那么,DI 容器要解决的问题是什么呢?它解决的是组件创建和组装的问题,但是为什么这是一个需要解决的问题呢?这就需要我们了解一下组件的创建和组装。
在前面的课程中,我讲过,软件设计需要有一个分解的过程,所以,它必然还要面对一个组装的过程,也就是把分解出来的各个组件组装到一起,完成所需要的功能。
为了叙述方便,我采用 Java 语言来进行后续的描述。
我们从程序员最熟悉的一个查询场景开始。假设我们有一个文章服务(ArticleService)提供根据标题查询文章的功能。当然,数据是需要持久化的,所以,这里还有一个 ArticleRepository,用来与持久化数据打交道。
熟悉 DDD 的同学可能发现了,这个仓库(Repository)的概念来自于 DDD。如果你不熟悉也没关系,它就是与持久化数据打交道的一层,和一些人习惯的 Mapper 或者 DAO(Data Access Object)类似,你可以简单地把它理解成访问数据库的代码。
class ArticleService {
//提供根据标题查询文章的服务