项目结构:
第一部分:Service对象解耦思路
如果在测试类TestSpring中使用
UserService userService = new UserServiceImpl();
就会导致一旦方法发生变化测试方法也需要变化,所以需要工厂设计模式来解耦
因此首先我们创建一个工厂类,里面专门new对象并返回,所以有类BeanFactory内的方法:
public static void getUserService(){
return new UserServiceImpl();
}
此时测试方法中只需要写:
UserService userService = BeanFactory.getUserService();
即可获取到对象,此时在测试类中便没有耦合
但是!
此时在工厂类中还是有耦合,因为工厂中还是new一个对象
所以对于工厂类的去耦合设计就要用到反射!
就需要如以下的代码一样获取对象UserService
Class clazz = Class.forName("com.atguigu.s1.UserServiceImpl");
UserService userService = (UserService)clazz.newInstance();
但是会发现forName()方法还是需要输入固定地址,因此还是存在耦合
所以我们可以写一个配置文件properties,使用其map集合存储数据的特性,在其中存入地址
userService=com.atguigu.s1.UserServiceImpl
之后便可以在工厂类中通过IO流获取到配置文件中的地址值填入forName()方法中
private static Properties env = new Properties();
static{
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
try {
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
此时配置文件中的key值为userService,value值为com.atguigu.s1.UserServiceImpl
就可以直接使用了:
try {
Class<?> clazz = Class.forName(env.getProperty("userService"));
userService = (UserService)clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
获取后便可直接return创建成功的对象了,此时在测试类和工厂类中便都不存在耦合了
此后如果需要修改或者替换UserServiceImpl(即UserService的实现类),那么不需要改动任何项目中的代码,只需要编写一个现在需要的实现类并实现UserService内的方法,并将这个新的实现类的地址替换properties配置文件中原来的地址即可.
第二部分:Dao对象解耦思路
由于我们在UserServiceImpl中需要创建UserDao对象,而如果直接new也会导致耦合,所以同Service解耦思路一样,先在配置文件中写入UserDao实现类的地址:
userDao = com.atguigu.s1.UserDaoImpl
之后通过IO流获取地址(同上)
最后在BeanFactory内创建getUserDao方法,获取地址创建对象并返回
public static UserDao getUserDao(){
UserDao userDao = null;
try {
Class<?> clazz = Class.forName(env.getProperty("userDao"));
userDao = (UserDao)clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return userDao;
}
即可完成Dao解耦
第三部分:BeanFactory中通用方法模板
由于在上方解耦过程中可以发现最终在BeanFactory内的代码都有一定的重复,如为Service解耦和为Dao解耦时,代码都有大部分相似:
public static UserService getUserService() {
UserService userService = null;
try {
Class<?> clazz = Class.forName(env.getProperty("userService"));
userService = (UserService) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return userService;
}
public static UserDao getUserDao() {
UserDao userDao = null;
try {
Class<?> clazz = Class.forName(env.getProperty("userDao"));
userDao = (UserDao) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return userDao;
}
因此我们可以为BeanFactory提供一个通用方法 :
public static Object getBean(String key){
Object ret = null;
try {
Class<?> clazz = Class.forName(env.getProperty(key));
ret = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
这样此后创建对象只需要在配置文件中写好地址之后再调用getBean方法传入key值就可以获得对应的对象了.