什么是程序的耦合?
- 耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接 口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间 的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强, 同时表明其独立性越差(降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软 件设计中独有的,但是我们只讨论软件工程中的耦合。
- 在软件工程中, 耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越 高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为 衡量模块独立程度的标准。
耦合的分类
- 内容耦合。公共耦合。外部耦合 。控制耦合 。标记耦合 。数据耦合。非直接耦合 。
内聚与耦合
- 内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩 展。 内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述 的是模块内的功能联系。耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决 于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低 耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依 存度却要不那么紧密。
- 内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意 味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
传统JDBC存在的耦合性问题及解耦思想
问题代码
try {
//1,注册驱动
DriverManager.registerDriver(new Driver());
//2,获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///test", "root", "root");
//3,获取执行sql对象
PreparedStatement statement = connection.prepareStatement("update tb_user set username = ? where id = ?");
//4,执行sql
statement.setString(1,"hahaha"); statement.setLong(2,1);
//5,释放资源
connection.close();
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
分析
-
实际开发中,解耦的本质
将编译期依赖变更为运行时依赖 -
解耦思路
使用反射创建对象,尽量少使用new关键字 使用配置文件存储要创建对象的全类名
之前三层架构中存在的耦合性问题及解决方案
问题代码
//Web层
public class UserServlet extends HttpServlet{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
UserService userService = new UserServiceImpl();
......
}
}
//Service层
public class UserServiceImpl implements UserService {
public void login(User user){
UserDao userDao = new UserDaoImpl();
......
}
}
//Dao层
public class UserDaoImpl implements UserDao {
public void login(User user){
......
}
}
解决思路1
使用工厂模式、反射、xml配置文件
public class MyApplicationContext {
private String path;
private Map<String,String> map = new HashMap<>();
public MyApplicationContext1() {
}
public MyApplicationContext1(String path) {
this.path = path;
parseXML(path);
}
private void parseXML(String path) {
SAXReader saxReader = new SAXReader();
try {
Document document =
saxReader.read(MyApplicationContext1.class.getClassLoader().getResourceAsStream( path));
Element beansEle = document.getRootElement();
List<Element> beanEles = beansEle.elements();
for (Element beanEle : beanEles) {
String id = beanEle.attributeValue("id");
String className = beanEle.attribute("class").getValue();
map.put(id,className);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String id){
try {
return Class.forName(map.get(id)).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
代码测试
public class Demo01 {
public static void main(String[] args) {
MyApplicationContext applicationContext = new MyApplicationContext("applicationContext.xml");
Object userService1 = applicationContext.getBean("userService");
Object userService2 = applicationContext.getBean("userService");
System.out.println(userService1 == userService2);
}
}
能够创建出对象,但是测试结果为false,说明由工厂类创建出来的实例是多例的!
- 思路1存在的问题
由工厂类创建出来的实例是多例的,如果改成单例,会提高效率
public class MyApplicationContext {
private String path;
private Map<String,Object> map = new HashMap<>();
public MyApplicationContext() {
}
public MyApplicationContext(String path) {
this.path = path;
parseXML(path);
}
private void parseXML(String path) {
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(MyApplicationContext.class.getClassLoader().getResourceAsStream(p ath));
Element beansEle = document.getRootElement();
List<Element> beanEles = beansEle.elements();
for (Element beanEle : beanEles) {
String id = beanEle.attributeValue("id");
String className = beanEle.attribute("class").getValue();
Object obj = Class.forName(className).newInstance();
map.put(id,obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String id){
return map.get(id);
}
}