控制反转
情景
先看下面这样一个例子:
定义一个UserDao接口,用来获取用户数据
package com.ys.dao;
public interface UserDao {
void getUser();
}
在写两个实现UserDao接口的类
UserDaoImpl.java
package com.ys.dao;
public class UserDaoimpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户的数据");
}
}
UserDaoMySqlImpl.java
package com.ys.dao;
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
写调用dao层的service层
UserService.java
package com.ys.service;
public interface UserService {
void getUser();
}
UserServiceImpl.java
package com.ys.service;
import com.ys.dao.UserDao;
import com.ys.dao.UserDaoimpl;
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void getUser() {
userDao = new UserDaoimpl();
userDao.getUser();
}
}
测试
import com.ys.dao.UserDao;
import com.ys.dao.UserDaoMysqlImpl;
import com.ys.dao.UserDaoimpl;
import com.ys.service.UserService;
import com.ys.service.UserServiceImpl;
import org.junit.Test;
public class MyTest {
@Test
public void Test1() {
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();
}
}
注意看上面的程序,我们在主函数中的service中只调用了UserDao接口其中一个实现类UserDaoImpl,当我们想再次调用UserDao接口的另一个实现类UserDaoMySqlImpl时,我们得改动UserServiceimpl的代码如下:
package com.ys.service;
import com.ys.dao.UserDao;
import com.ys.dao.UserDaoMysqlImpl;
import com.ys.dao.UserDaoimpl;
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void getUser() {
userDao = new UserDaoMysqlImpl();
userDao.getUser();
}
}
以上的改动明显违背了开闭原则,当我们要扩展原有业务时,要在原有的程序中修改显然是可取的,这将是一项很大的工程量。那也没有更好的办法能在不改动原有业务的代码的情况下又可以扩展“新业务"呢?
我们尝试对UserServiceImpl做如下的改动,增加一个set方法,来接收传进来的一个UserDao接口的实现类
import com.ys.dao.UserDao;
import com.ys.dao.UserDaoMysqlImpl;
import com.ys.dao.UserDaoimpl;
import com.ys.service.UserService;
import com.ys.service.UserServiceImpl;
import org.junit.Test;
public class MyTest {
@Test
public void Test1() {
// 用户实际调用的是业务,Dao层不需要接触
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl());
// userService.setUserDao(new UserDaoimpl());
userService.getUser();
}
}
从上面的改动后的程序来看,即使我们更改使用不同的业务,那么我们也不用对原有的dao层,service层做改动,而是在主程序中被动接收一个参数,就可以很好完成扩展 ,这样也符合开闭原则。