编程思想 控制反转(IOC)
控制反转,IOC,Inversion of Control。
一、传统方式
1. 说明
由于对象单一职责原则,如果一个对象要完成某件事情,往往要依赖于其它对象。
在传统的做法中,如果程序中一个对象依赖另外一个对象(比如需要调用该对象的实例方法),就在该对象内部通过 new 的方式直接创建其依赖的对象。
这种做法有两大特点:
- 对象的依赖关系写死在程序之中,影响了程序的可扩展性
- 对象之间相互依赖、严重耦合,增大了维护成本
2. 示例
XxxDao 接口
1
2
3public interface UserDao {
void getUser();
}XxxDapImpl 实现类
1
2
3
4
5
6public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}XxxService 接口
1
2
3public interface UserService {
void getUser();
}XxxServiceImpl 实现类
1
2
3
4
5
6
7
8public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}Client 调用方
1
2
3
4
5
6public class CustomerClient {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
在 UserServiceImpl 类中需要调用 UserDao 的方法,因此直接实例化其实现类。
3. 缺点
(1) 可扩展性差
假设现在 UserDao 又有了其它实现类 UserDaoImplMySQL、UserDaoImplOracle,希望能够换用不同的实现类。
一个容易想到的解决方式是修改源代码:
1 |
|
由于对象的依赖关系写死在程序之中,一旦用户提出新需求便需要修改源代码,可扩展性差。
(2) 维护成本高
假设现在希望将 UserDaoImpl 类更改为 UserDaoImplMySQL 类。
但如果有不止一个对象依赖了 UserDaoImpl 类,便需要进行大量重复修改。
由于对象之间相互依赖、严重耦合,一旦需要修改某个对象,便需要相应修改所有依赖它的对象,增大了维护成本。
二、IOC 方法
1. IOC
为解决传统方式的两个缺点,IOC 应运而生。
IOC,即控制反转。所谓的控制反转,就是把对对象的控制权由程序本身转移到外部,不再让程序创建和管理对象,而是让程序被动地接收对象。
2. 简单示例
XxxDao 接口
1
2
3public interface UserDao {
void getUser();
}XxxDapImpl 实现类
1
2
3
4
5
6public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}XxxDapImplMySQL 实现类2
1
2
3
4
5
6public class UserDaoImplMySQL implements UserDao {
@Override
public void getUser() {
System.out.println("MySQL获取用户数据");
}
}XxxService 接口
1
2
3public interface UserService {
void getUser();
}XxxServiceImpl 实现类
1
2
3
4
5
6
7
8
9
10
11
12public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}Client 调用方
1
2
3
4
5
6
7public class CustomerClient {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoImplMySQL());
userService.getUser();
}
}
通过 UserServiceImpl 类的 setUserDao()
方法,使得调用方可以主动控制对象的创建,而程序只是定义接口,并被动地等待对象。
三、IOC 的实现
1. 依赖注入(DI)
容器会负责把依赖装配进对象之中。
2. 依赖查找(DL)
当对象需要依赖时,通过容器提供的方法向容器获取。