首先我们先看一个例子。以下是代码的结构。
public interface UserDAO {
/**
* 根据id删除用户
*/
void deleteById();
}
public class UserDAOImplForMySQL implements UserDAO {
@Override
public void deleteById() {
System.out.println("使用MySQL数据库删除信息....");
}
}
public interface UserService{
/**
* 删除用户信息
*/
void deleteUser();
}
public class UserServiceImpl implements UserService {
private UserDAO userDAO = new UserDAOImplForMySQL();
@Override
public void deleteUser() {
userDAO.deleteById();
}
}
public class UserAction {
private UserService userService = new UserServiceImpl();
/**
* 删除用户信息的请求
*/
public void deleteRequest() {
userService.deleteUser();
}
}
public class UserTest {
@Test
public void test() {
UserAction userAction = new UserAction();
userAction.deleteRequest();
}
}
以上代码代码现在看起来没有什么问题对吧。
好的。现在我有一个新的需求:我想要使用付费的 Oracle。
此时怎么做呢?当然就是新建一个 Oracle 的实现类了。
public class UserDAOImplForOracle implements UserDAO {
@Override
public void deleteById() {
System.out.println("使用Oracle数据库删除信息....");
}
}
此时,直接执行还是使用的 MySQL。我们需要去改变之前写好的代码,才可以实现这个需求。
public class UserServiceImpl implements UserService {
private UserDAO userDAO = new UserDAOImplForOracle();
@Override
public void deleteUser() {
userDAO.deleteById();
}
}
这违背了软件开发原则中的 开闭原则 和 依赖倒置原则。
以下先分别介绍这两种原则。
开闭原则(OCP)
- OCP 开闭原则是软件七大开发原则当中最基本的一个原则。
- OCP 开闭原则:
-
- 在软件开发过程中应当对扩展开放,对修改关闭。
- 在软件开发过程中,通过添加额外的类对原先程序已有的功能进行扩展是没问题的,但是如果因为要进行功能扩展而修改之前运行正常的程序,这是不被允许的。
- 因为一旦修改之前运行正常的程序,那么项目整体就要进行重新测试,这会导致额外的开销和资源消耗,并且测试过程相当麻烦。
- OCP 开闭原则是最核心的、最基本的,其他的六个开发原则都是为这个原则服务的。
- 是否违反 OCP 开闭原则的判断:
-
- 只要你在扩展系统功能的时候,没有修改以前写好的代码,那么你就是符合 OCP 原则的。
- 反之,如果在扩展系统功能的时候,你修改了之前的代码,那么这个设计是失败的,违背了OCP原则。
依赖倒置原则(DIP)
- 依赖倒置原则,就是不再显示的建立类之间的关联关系,而是面向接口编程,面向抽象编程,不要面向具体编程,从而降低程序的耦合度,提高程序的扩展力,增强代码复用性。
- 依赖倒置原则的目的:降低程序的耦合度,提高程序的扩展力,增强代码复用性。
- 是否符合依赖倒置原则:
-
- 上 不依赖 下,就是符合,即类的实例对象之间没有明确固定在代码中的依赖关系。
- 上 依赖 下,就是违背。只要“下”一改动,“上”就受到牵连。
- 符合依赖倒置原则的编程思想:控制反转。
控制反转(IoC)
- 当前程序的设计,显然既违背OCP,又违背DIP,可以采用“控制反转”这种编程思想来解决这个问题。
- 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计思想,可以用来降低代码之间的耦合度,符合依赖倒置原则。
-
- 由于控制反转思想出现的比较新,所以没有被纳入GoF23种设计模式范围内。
- 控制反转的核心思想:
-
- 将对象的创建权交出去。
- 将对象和对象之间关系的管理权交出去。
- 对象的创建和对象之间关系的维护都由第三方容器来负责。
- 控制反转中的反转是两件事:
-
- 第一件事:不在程序中采用硬编码的方式来new对象了,将new对象的权利交出去。
- 第二件事:不在程序中采用硬编码的方式来维护对象的关系了,对象之间关系的维护权交出去了。
- 控制反转思想的实现:依赖注入。
依赖注入(DI)
- 控制反转的实现方式有多种,其中比较重要的叫做:依赖注入(Dependency Injection,简称DI)。
- 依赖注入,用于实现对象之间关系的建立。
- 控制反转是思想。依赖注入是这种思想的具体实现。
- 依赖注入DI,又包括常见的两种方式:
-
- 第一种:set注入(执行set方法给属性赋值)
- 第二种:构造方法注入(执行构造方法给属性赋值)
- 依赖注入 中 “依赖”是什么意思? “注入”是什么意思?
-
- 依赖:A对象和B对象的关系。
- 注入:是一种手段,通过这种手段,可以让A对象和B对象产生关系。
- 依赖注入:对象A和对象B之间的关系,靠注入的手段来维护。而注入包括:set注入和构造注入。
术语小结
- OCP:开闭原则(开发原则)
- DIP:依赖倒置原则(开发原则)
- IoC:控制反转(一种思想,一种新型的设计模式)
- DI:依赖注入(控制反转思想的具体实现方式)
什么是Spring
Spring 框架实现了控制反转IoC这种思想。
- Spring框架可以帮你new对象。
- Spring框架可以帮你维护对象和对象之间的关系。
Spring是一个实现了IoC思想的容器。
当然,Spring 不止实现了IoC,还有以下的特性。
- Spring是一个开源框架。
- Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
-
- Spring实现了控制反转思想,Spring框架可以帮你维护对象和对象之间的关系
- Spring实现了面向切面编程
- 由于我们可以将创建对象交给Spring负责,所以Spring也是一个存放对象的容器
- Spring为简化开发而生,让程序员只需关注核心业务的实现,尽可能的不再关注非业务逻辑代码(事务控制,安全日志等),这得益于AOP。
Spring 8大模块
- Spring5版本之后是8个模块。在Spring5中新增了WebFlux模块。
Spring 的特点
- 轻量
-
- 完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布,并且Spring所需的处理开销也是微不足道的。
- Spring是非侵入式的:spring框架的运行不需要依赖其他框架
- 控制反转
-
- Spring实现了控制反转思想
- 面向切面
-
- Spring提供了面向切面编程的丰富支持
- 允许开发者只需专注于业务逻辑的开发,与核心业务无关的代码可以以切面的方式加入核心业务代码的执行过程中,将核心业务的执行流程看成是纵向执行的,与核心业务无关的代码(如事务、日志等)可以以横向切面的方式加入核心业务的执行过程中
- 容器
-
- Spring 可以包含并管理应用对象的配置和生命周期,即Spring可以负责对象的创建到对象的销毁这整个生命周期过程中对象的维护和管理,Spring就好比一个存放和管理对象的容器
- 框架
-
- Spring可以将简单的组件配置、组合成为复杂的应用。
Spring 对 JDK 的要求
- Spring6要求JDK最低版本是Java17