高耦合的代码
我想要写一段程序,该程序有dao层和service层,dao层有接口UserDao,定义了一个方法叫做sayHello(),并且在dao层定义两个类MysqlDao和OracleDao,他们都实现了UserDao接口,并且实现了sayHello()方法,如图和代码所示
UserDao接口的代码如下
package com.loubin.dao;public interface UserDao {public void sayHello(); }
MysqlDao类的代码如下
package com.loubin.dao;public class MysqlDao implements UserDao{@Overridepublic void sayHello() {System.out.println("正在使用mysql访问数据");} }
Oracle类的代码如下
package com.loubin.dao;public class OracleDao implements UserDao{@Overridepublic void sayHello() {System.out.println("正在使用oracle访问数据");} }
接下来我在service层定义了UserService接口,并且定义了UserServiceImpl类来实现该接口,该类调用UserDao接口,代码实现如下
UserService接口的代码如下
package com.loubin.service;public interface UserService {public void sayHello(); }
UserServiceImpl类的代码如下
package com.loubin.service;import com.loubin.dao.MysqlDao; import com.loubin.dao.UserDao;public class UserServiceImpl implements UserService{private UserDao userDao = new MysqlDao();@Overridepublic void sayHello() {userDao.sayHello();}@Overridepublic String toString() {return "UserServiceImpl{" +"userDao=" + userDao +'}';}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;} }
测试代码TestUserService如下
package com.loubin;import com.loubin.service.UserService; import com.loubin.service.UserServiceImpl; import org.junit.Test;public class TestUserService {@Testpublic void testSayHello(){UserService userService = new UserServiceImpl();userService.sayHello();}}
测试结果如下
上面的代码有个问题,那就是我在UserServiceImpl类中,显示定义了属性userDao,并且令他为类Mysql的对象,但是如果测试代码的需求(可以认为是客户的需求)变了,需要使用OracleDao类来实现sayHello,那么我需要在UserServiceImpl类中将
set注入实现控制反转
如果让用户自己选择想用UserDao的哪一个实现类,并且自己将选择的实现类传入到UserServiceImpl中,这样程序员就不需要修改UserServiceImpl了,将控制的权限从程序员反转到了客户本身,这就是反转控制。具体实现如下
新的UserServiceImpl代码,增加了构造函数,并且不在类里面显示定义UserDao的实现了
package com.loubin.service;import com.loubin.dao.MysqlDao; import com.loubin.dao.UserDao;public class UserServiceImpl implements UserService{private UserDao userDao;public UserServiceImpl(UserDao userDao) {this.userDao = userDao;}@Overridepublic void sayHello() {userDao.sayHello();}@Overridepublic String toString() {return "UserServiceImpl{" +"userDao=" + userDao +'}';}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;} }
测试代码如下,现在客户自己实现UserDao,想用MysqlDao还是OracleDao都行了
package com.loubin;import com.loubin.dao.MysqlDao; import com.loubin.dao.UserDao; import com.loubin.service.UserService; import com.loubin.service.UserServiceImpl; import org.junit.Test;public class testUserService {@Testpublic void testSayHello(){UserDao userDao = new MysqlDao();UserService userService = new UserServiceImpl(userDao);userService.sayHello();}}
通过spring的ioc容器管理
使用ioc容器进行对象的托管,来代替上一小节的set注入
配置ioc容器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="mysqlDao" class="com.loubin.dao.MysqlDao"></bean><bean class="com.loubin.dao.OracleDao" id="oracleDao"></bean><bean class="com.loubin.service.UserServiceImpl" id="service"><property name="userDao" ref="mysqlDao"></property></bean> </beans>
测试代码变成如下代码
package com.loubin;import com.loubin.dao.MysqlDao; import com.loubin.dao.UserDao; import com.loubin.service.UserService; import com.loubin.service.UserServiceImpl; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class testUserService {@Testpublic void testSayHello(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService service = (UserService) context.getBean("service");service.sayHello();}}