2. IoC理论推导
之前在操作数据库时,我们首先需要在Dao层定义接口,定义增删改查等抽象方法,然后在Dao层定义实现类来实现这些方法:
UserDao接口
package com.neu.dao;
public interface UserDao {
//从数据库中获取用户数据
void getUser();
}
UserDaoImpl实现类
package com.neu.dao;
public class UserDaoImpl implements UserDao{
//实现接口中的方法,操作数据库获取用户数据
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
在Service层中定义和Dao层相同的接口,然后定义一个实现类来实现这些方法,使用实现的方法调用Dao层的接口,使用户面向业务层,而不是直接操作Dao层。
UserService接口
package com.neu.service;
public interface UserService {
//定义与Dao层接口相同的方法
void getUser();
}
UserServiceImpl实现类
package com.neu.service;
import com.neu.dao.UserDao;
import com.neu.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
/**
* 业务层中实现的方法只用来调用Dao层实现类中的方法
*/
public void getUser() {
userDao.getUser();
}
}测试代码:
import com.neu.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是service层,dao层他们不需要接触
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();//调用业务层来实现功能
}
}
==这里就会有一个问题:如果Dao层中有多个实现类需要操作的话,需要怎么办?==
下图是之前的做法,UserDao对象指向不同的实现类(子类)实例,来调用不同实现类的重写方法:
这里就会遇到一个很大的问题,==那就是如果再增加需求,就需要再次修改业务层的代码,如果项目很大的话,就需要修改很多的代码,这明显不是一个好的程序。==
所以,需要换一个思路来解决这个问题:
这样,用户可以自己去选择调用哪个,而不需要在业务层上做修改:
总结:
修改前和修改后的区别:
- 修改前,程序是主动创建对象,控制权在程序员手里,程序员需要去手动修改业务层创建哪个对象去调用哪个实现类
- 之后set注入之后,程序不再具有主动性,而是变成了被动接受对象,传入哪个实现类对象,就可以调用哪个实现类
这种思想,从本质上解决了问题,程序猿不用再去管理对象的创建了,大大降低了系统的耦合性,可以更加专注在业务的实现上,这就是IoC的原型。
IoC的本质:
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把二者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到零配置的目的。
控制反转是一种通过(XML或注解)并通过第三方去生产或获取特定对象的方法。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
写完第一个Spring Hello程序,回来用Spring的方式改造下上面的例子: