1. [核心思想] Spring 启示录:从设计原则到控制反转

1. [核心思想] Spring 启示录:从设计原则到控制反转
Prorise1. [核心思想] Spring 启示录:从设计原则到控制反转
摘要: 本章从 OCP 开闭原则 与 DIP 依赖倒置原则 出发,引出 Spring 的核心思想——控制反转 (IoC),为理解其解耦能力奠定理论基石。
1.1. 软件开发的“初心”:OCP 开闭原则
我们进行软件开发时,最核心的目标之一就是构建易于维护和扩展的系统。开闭原则(Open-Closed Principle, OCP)正是指导我们实现这一目标的基础性原则,它要求一个软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。
在传统的、层级分明的代码结构中,我们常常会遇到一个棘手的问题:高耦合。这意味着代码模块之间紧密地绑定在一起。
从上图可以很明显地看出,上层 是依赖 下层 的。UserController
依赖 UserServiceImpl
,而 UserServiceImpl
又依赖 UserDaoImplForMySQL
。这种依赖关系会导致一个连锁反应:下层模块一旦发生任何改动,上层模块极有可能需要随之修改。这便是所谓的“牵一发而动全身”。
当我们需要为软件增加新功能时,我们应当通过 增加新的代码(例如,新的类)来实现,而不是去修改那些已经被测试过且运行正常的旧代码。修改旧代码的风险在于,它可能会引入未知的缺陷,迫使我们对整个项目进行全方位回归测试,这是一个极其耗时且繁琐的过程。
1.2. 解耦的钥匙:依赖倒置原则 (DIP)
为了破解高耦合的困局,实现开闭原则,我们需要一把关键的“钥匙”——依赖倒置原则 (Dependence Inversion Principle, DIP)。它倡导我们应该 面向抽象(接口)编程,而不是面向具体实现编程。
核心提示:包括开闭原则、依赖倒置原则在内的软件设计七大原则,它们的共同目标都是在为“解耦”服务。
你可能会说,上图中的代码已经遵循了“面向接口编程”的规范。确实,UserService
依赖的是 UserDao
接口。但问题出在对象的创建上:new UserDaoImplForOracle()
这行代码,让我们再次与具体的实现类产生了耦合。
依赖倒置原则的目标是让 上层不再依赖下层,实现依赖关系的“倒置”。完全符合依赖倒置原则的理想代码中,UserService
只持有 UserDao
接口的引用,完全不出现 new
任何具体实现类的代码。
这种理想的代码会带来一个显而易见的问题:userDao
引用是 null
,运行时必然会导致空指针异常。要解决这个异常,我们必须回答两个核心问题:
- 第一个问题:谁来负责对象的创建 ?(谁来执行
new UserDaoImplForOracle()
?) - 第二个问题:谁来负责把创建的对象赋到属性上 ?(谁来把对象赋值给
userDao
属性?)
值得庆幸的是,Spring 框架正是为解决这两个核心问题而生的。它能帮我们创建对象,并自动地将这些对象赋值给需要的属性,建立它们之间的依赖关系。
这种将对象的创建权和对象关系的管理权从我们的业务代码中移交出去的编程范式,就引出了 Spring 的核心思想——控制反转。
1.3. Spring 的灵魂:控制反转 (IoC) 与依赖注入 (DI)
控制反转(Inversion of Control, 缩写为 IoC),是面向对象编程中的一种核心设计思想,其主要目的就是用来 降低代码之间的耦合度。它的核心理念是:将对象的创建权交出去,将对象和对象之间关系的管理权交出去,由一个独立的第三方容器来负责这一切的创建与维护工作。
IoC 是一种现代设计思想,其理念与 GoF 23 种经典设计模式一脉相承,但因其出现较晚而未被收录。
控制反转(IoC)是一种思想,而 依赖注入(Dependency Injection, 缩写为 DI)是实现这种思想最常见、最重要的方式。我们将在后续章节中详细学习,DI 的具体实现又包括两种主要方式:
- Set 方法注入
- 构造方法注入
而 Spring 框架,正是一个完美实现了 IoC 思想,并以 DI 作为其核心机制的顶级容器框架。