Spring解耦和耦合

程序中的耦合和解耦

什么是程序的耦合

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差(降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。

总结:在软件工程中,耦合指的就是指对象之间的依赖关系。对象之间的依赖程度越高,耦合度就越高。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。

降低程序之间的依赖程度,即降低程序之间的耦合度的过程就叫做解耦。

例如:早期的Jdbc操作中,在注册数据库驱动时,为什么采用的是Class.forName的方式,而不是采用DriverManager.registerDriver的方式?

public class TestJdbc {
  public static void main(String[] args) throws Exception {
    //1.注册数据库驱动
    // DriverManager.registerDriver( new Driver() );
    Class.forName("com.mysql.jdbc.Driver");
    //2.获取数据库连接
    //3.获取传输器
    //4.发送sql到服务器执行并返回执行结果
    //5.处理结果
    //6.释放资源
  }
}

除了DriverManager.registerDriver会导致驱动注册两次外,更重要的是,如果使用这种方式,JDBC程序就会依赖于数据库的驱动类(MySQL的Driver类),如果后期程序因数据量和性能原因升级到Oracle数据库,就需要修改程序源代码——重新导入新的驱动类,这会增加很多不必要的麻烦!

而是用Class.forName方式注册驱动,这样的好处是Jdbc程序不再依赖具体的驱动类,即使删除(或不导入)mysql驱动包,程序依然可以编译(当然不可能运行,因为运行时肯定需要依赖驱动)。

此时类中仅仅是将mysql驱动类的全限定类名写死在程序中(只是一个字符串),可以将这个字符串提取到配置文件中,后期可以通过修改配置文件(而不用修改程序代码)轻松的替换数据库产品。

使用工厂模式解耦

我们可以创建一个工厂, 使用工厂来创建对象. 而不是我们手动去new

在maven的resource下创建配置文件

EmpService=com.test.service.EmpServiceImpl
EmpDao=com.test.dao.EmpDaoImpl

编写工厂类

package com.test.factory;

import java.io.InputStream;
import java.util.Properties;

/**
 * 使用工厂+接口+配置文件 (降低)程序之间的耦合性(也就是以来成都)
 * 
 * 作用: 帮我们创建程序中所需要的对象
 * (而不是通过new的方式获取对象, 因为new对象会造成耦合性提升)
 * 目的: 当我们替换某一层(类)时, 不需要修改java源代码, 就可以实现
 * 
 * 工程: BeanFactory
 * 配置文件: config.properties (放在src/main/resource下)
 * 		配置文件中负责配置Service层的实现类和Dao层的实现类
 * 		也就是说, 配置的是哪一个实现类, 我们就获取哪一个实现类的示例
 * 		如果将来要替换实现类, 只需要修改配置文件中配置的实现类即可!
 * 
 * 接口: EmpService, EmpDao
 */
public class BeanFactory {
	
	private static Properties prop = null;
	static {
		// 为prop进行初始化
		prop = new Properties();
		try {
			// 加载config.properties文件, 获取指向该文件的流对象
			// 通过当前类的字节码对象获取加载当前类的加载器
			ClassLoader loader = BeanFactory.class.getClassLoader();
			InputStream in = loader.getResourceAsStream("config.properties");
			prop.load(in);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 根据接口名(EmpService, EmpDao) 获取该接口对应的子类实例
	 */
	public static Object getBean(String key) {
		try {
			// 通过key(接口名)获取该接口对应了类的全限定类名
			String className = prop.getProperty(key);
			// 通过子类的全限定类名, 获取该子类的字节码对象, 通过字节码对象获取类的实例
			Object obj = Class.forName(className).newInstance();
			return obj;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

现在我们创建对象可以使用, 不用每次都去new, 大大降低了程序的耦合性

private EmpService service = (EmpService) BeanFactory.getBean("EmpService");
posted @ 2020-06-22 12:55  zpk-aaron  阅读(741)  评论(0编辑  收藏  举报