传统的调用业务层是:
CustomerServiceImpl csi = new CustomerServiceImpl();
通过面向接口编程改进过后:
CustomerService cs = new CustomerServiceImpl();
这种还是不好,因为如果我要修改底层的实现类,还是要修改源代码
我们编程应该遵循opc原则:open-close:对程序扩展是开放的,对修改源码是关闭的
所以我们需要降低程序之间的耦合性,解耦和操作
在接口和实现类之间用工厂来解耦和
就像
CustomerService cs = new CustomerServiceImpl();我们要通过工厂模式改造成:
CustomerService cs = BeanFatory.getCustomerService();
所以在BeanFactory中的代码应该是:
class BeanFactory { public static CustomerService getCustomerService() { return new CustomerServiceImpl(); } }
但是我们发现这样做也不好,因为实现类跟这个工厂耦合了,而且如果有其他的service,我们还
需要为每个service都写一个工厂的方法
在这个基础上,我们需要进一步改进得连工厂都不需要修改
所以用工厂+反射+配置文件来解耦和
在xml文件中配置接口名,和实现类的绝对路径
其实这就是最简单的控制反转
在src下建立一个xml文件
例如我们在src下建立了一个applicationContext.xml文件
里面配置了service层和到层的解耦和文件
<?xml version="1.0" encoding="UTF-8"?> <beans> <!-- 配置service层解耦 --> <bean id="CategoryService" class="com.project.service.imp.CategoryServiceImpl"></bean> <bean id="ProductService" class="com.project.service.imp.ProductServiceImpl"></bean> <bean id="UserService" class="com.project.service.imp.UserServiceImpl"></bean> <!-- 配置dao层解耦 --> <bean id="CategoryDao" class="com.project.dao.imp.CategoryDaoImpl"></bean> <bean id="ProductDao" class="com.project.dao.imp.ProductDaoImpl"></bean> <bean id="UserDao" class="com.project.dao.imp.UserDaoImpl"></bean> </beans>
写一个BeanFactory类
public class BeanFactory { public static Object getBean(String id) { try { //用类加载器解析xml文件 SAXReader reader = new SAXReader(); Document document = reader.read(BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml")); //xpath技术获得bean元素 Element element = (Element) document.selectSingleNode("//bean[@id='"+id+"']"); //拿到class属性里面的值 String value = element.attributeValue("class"); //获得反射对象 Class clazz = Class.forName(value); //获得实例 return clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } } }
这样我们要调用service层就成了
CategoryService cs = (CategoryService )BeanFactory.getBean("CategoryService ");