是什么?
控制反转(IoC)是一种设计原则,它将控制权从应用程序代码中转移到外部容器或框架。传统的程序设计中,应用程序代码通常负责创建和管理对象之间的依赖关系,而在IoC容器中,对象的创建和管理由容器来负责。IoC容器通过反转了传统的对象创建和管理方式,使得应用程序更加灵活、可扩展,并且更容易进行单元测试。
依赖注入(DI)是IoC的一种实现方式,它是指将对象的依赖关系通过外部注入的方式来实现。在DI中,对象不再负责自己的依赖关系的创建和管理,而是通过构造函数、属性或者方法的参数等方式,由外部容器来注入所需的依赖对象。
综合来说,IoC容器通过控制反转的方式来管理对象的创建和依赖关系,而依赖注入则是IoC的一种具体实现方式,通过外部注入的方式来实现对象之间的依赖关系。这些概念在现代的软件开发中被广泛应用,可以帮助提高代码的灵活性、可维护性和可测试性。
OCP原则:
什么是OCP?OCP是软件七大开发原则的最基本原则: 开闭原则 对扩展开放,对修改关闭。只要你在扩展功能的时候, 没有修改以前写好的代码, 那么你就是符合OCP原则的,反之, 如果在扩展系统功能的时候, 修改了之前的代码, 那么这个设计就是失败的, 违背了OCP原则.当进行系统功能扩展的时候, 如果动了之前稳定的程序, 修改了之前的程序, 之前所有的程序都需要程序进行测试, 这是非常麻烦的.
依赖倒置原则(DIP原则):
什么是依赖倒置原则?即面向接口编程, 面向抽象编程, 不要面向具体编程
目的是降低程序的耦合度, 提高扩展力。
上(业务层的代码) 不依赖 下(持久层的代码), 就是符合依赖倒置上 依赖 下, 就是违背
只要 下 代码一改动, 上 就受到牵连。
class Order {
private Database database;
// 省略构造方法和其他属性方法
public void save() {
database.save(this);
}
}
class Database {
public void save(Order order) {
// 保存订单到数据库
}
}
在这个设计中,订单类直接依赖于具体的数据库类,这样一来,如果将来需要更换数据库操作方式,就需要修改订单类的代码,违反了开闭原则。
为了符合依赖倒置原则,我们可以进行重构。首先,定义一个抽象类或接口`Database`:
interface Database {
void save(Order order);
}
然后,订单类通过构造函数或setter方法注入一个`Database`对象,从而将具体的数据库实现与订单类解耦:
class Order {
private Database database;
public Order(Database database) {
this.database = database;
}
// 省略其他属性方法
public void save() {
database.save(this);
}
}
当需要使用特定的数据库实现时,我们只需要创建一个实现了`Database`接口的具体类,并将其传递给订单类:
这样,订单类与具体的数据库实现解耦,而且我们可以轻松地使用不同的数据库实现,而无需修改订单类的代码。
依赖倒置原则的目的是降低模块之间的耦合度,提高系统的灵活性和可维护性。通过面向抽象编程,并通过依赖注入的方式实现对象之间的解耦,可以使系统更容易扩展和修改,同时也方便进行单元测试和模块替换。总结起来,依赖倒置原则要求我们将高层模块的设计依赖于抽象,而不是具体实现细节
控制反转IoC
反转是什么呢? 反转的是俩件事, 第一件事: 我不在程序中采用硬编码的方式来new对象了 (new对象的权利交出去了) 第二件事: 我不在程序中采用硬编码的方式来维护对象的关系了 (对象之间的维护全交出去了)。
怎么实现呢?在spring框架中使用方式是依赖注入 ,简称为 DI
(DependencyInjection)。
所以:控制反转是思想, 依赖注入是这种思想的具体实现
依赖注入DI:
依赖注入DI, 包括常见的俩种方式:
- 第一种, set注入 (执行set方法给属性赋值)
- 第二种, 构造方法注入 (执行构造方法给属性赋值)public class UserServiceImpl implements UserService{
private UserDao userDao;
// set注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
// 构造方法注入
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void deleteUser() {
userDao.deleteById();
}
}
依赖注入中, "依赖"是什么意思? "注入"是什么意思?
依赖: 对象和对象之间的关联关系(A对象中有B, B对象中有C)
注入: 是一种手段, 通过这种手段, 可以让A对象和B对象产生关系
依赖注入: 对象A和对象B之间的关系, 靠注入的手段来维护, 而注入包括: set注入和构造注入
Spring通过依赖注入的方式来完成Bean管理
Bean管理说的是:
Bean对象的创建
Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)
Spring是怎么实例化对象的?
默认情况下, spring通过反射机制, 调用类的无参构造方法来实例化对象, 实现原理如下:
- class clazz = Class.forName("com.powernode.bean.User");
- Object obj = clazz.newInstance();
关于Bean的创建和使用
public class HelloWorld {
private String message;
public void setMessage(String message) {
this.message = message;
}
public void getMessage() {
System.out.println("Your Message : " + message);
}
}
然后,在Spring的配置文件中声明该Bean:
<bean id="helloWorld" class="com.example.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
配置文件中,id属性指定了Bean的唯一标识符,class属性指定了Bean的类型,property元素用于设置Bean的属性。
最后,在Java代码中使用该Bean
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
}
// 不想强制类型转换, 可以使用下面的代码: (通过第二个参数, 指定返回的bean的类型)
HelloWorld obj = ctx.getBean("helloWorld", HelloWorld.class);