1.1 程序中耦合概念理解
在软件工程中, 耦合指的就是就是对象之间的关联性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。 软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。 划分模块的一个准则就是高内聚低耦合。
高内聚,低耦合:简单来说,就是类内部的关系越紧密越好,类与类之间的关系越少越好。
1.2 程序中耦合
package com.sunny.test;
import org.junit.Test;
import java.sql.*;
/**
* 耦合:
* 指的是程序中的依赖关系
* 依赖关系还有很多种分类
* 现在看到的是类的依赖
* 解决依赖关系:
* 使用反射注册驱动
* 使用反射创建对象产生的问题:
* 驱动类字符串在代码中写死了,如果遇到修改,又要改源码
* 解决写死了字符串的问题:
* 使用配置文件
* 在项目开发过程中,我们应该做到:
* 编译不依赖,运行时才依赖。
*/
public class jdbcdemo01 {
@Test
public void test01() throws SQLException {
//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatisdb", "root", "root");
//3.获取操作数据库的预处理对象
PreparedStatement pstm = conn.prepareStatement("select * from account");
//4.执行SQL语句
ResultSet rs = pstm.executeQuery();
//5.遍历结果集
while(rs.next()) {
System.out.println(rs.getString("name"));
}
//6.释放资源
rs.close();
pstm.close();
conn.close();
}
}
1.3 解决思路
- 我们在使用jdbc注册驱动的时候,代码如下:Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串。
- 好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译(运行就不要想了,没有驱动不可能运行成功的) 。
- 同时,也产生了一个新的问题, mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置。
- 1.在开发中的三层架构分别是dao、service、controller,如何降低这三层的耦合度呢?
- 实现的目标:修改dao的实现、不用修改service层,实现service与dao的解耦。
步骤1:准备
dao接口
package com.sunny.dao;
public interface IAccountDao {
void save();
}
实现
package com.sunny.dao.impl;
import com.sunny.dao.IAccountDao;
public class AccountDaoImpl implements IAccountDao {
@Override
public void save() {
System.out.println("保存账户");
}
}
package com.sunny.dao.impl;
import com.sunny.dao.IAccountDao;
public class AccountDaoOracleImpl implements IAccountDao {
@Override
public void save() {
System.out.println("Oracle保存账户");
}
}
service接口
package com.sunny.service;
public interface IAccountService {
void save();
}
实现
package com.sunny.service.impl;
import com.sunny.dao.IAccountDao;
import com.sunny.dao.impl.AccountDaoImpl;
import com.sunny.factory.BeanFactory;
import com.sunny.service.IAccountService;
public class IAccountServiceImpl implements IAccountService {
//创建dao
//private IAccountDao accountDao = new AccountDaoImpl();
private IAccountDao accountDao = BeanFactory.getBean("accountDao",IAccountDao.class);
@Override
public void save() {
accountDao.save();
}
}
步骤2:工厂解耦
1.定义properties配置文件
2.定义工厂
package com.sunny.factory;
import java.lang.reflect.InvocationTargetException;
import java.util.ResourceBundle;
/**
* 创建对象的工厂,主要加载配置文件创建Service、dao对象
*/
public class BeanFactory {
/**
* 根据指定的key,读取配置文件创建对象
* @param key
* @param clazz
* @param <T>
* @return
*/
public static <T>T getBean(String key,Class<T> clazz) {
try {
//加载properties配置文件
//通过ResourceBundle加载配置文件
//1.只可以加载properties后缀的配置文件
//2.只能加载类路径下的properties配置文件
ResourceBundle bundle = ResourceBundle.getBundle("instance");
//3.根据key获取value com.sunny.dao.impl.AccountDaoImpl
String value = bundle.getString(key);
//4.创建对象返回
return (T) Class.forName(value).getConstructor().newInstance();
} catch (Exception e) {
//异常转型,调用者可以处理也可以不处理(灵活)
throw new RuntimeException(e);
}
}
}
3.修改service
package com.sunny.service.impl;
import com.sunny.dao.IAccountDao;
import com.sunny.dao.impl.AccountDaoImpl;
import com.sunny.factory.BeanFactory;
import com.sunny.service.IAccountService;
public class IAccountServiceImpl implements IAccountService {
// 创建dao
//private IAccountDao accountDao = new AccountDaoImpl();
// 新需求:更换了数据库改为oracle
//private IAccountDao accountDao = new AccountDaoOracleImpl();
// 分析:现在更改了数据库,dao重新写了实现,对sevice有影响,要修改代码。
// 期望:改dao,不修改service代码。(service与dao解耦的设计)
//创建dao
//private IAccountDao accountDao = new AccountDaoImpl();
private IAccountDao accountDao = BeanFactory.getBean("accountDao",IAccountDao.class);
@Override
public void save() {
accountDao.save();
}
}
4.测试
package com.sunny.test;
import com.sunny.factory.BeanFactory;
import com.sunny.service.IAccountService;
import org.junit.Test;
public class App2 {
@Test
public void test01(){
//通过工厂创建Service
IAccountService accountService = BeanFactory.getBean("accountService",IAccountService.class);
accountService.save();
}
}
2.1 Inversion Of Control(IOC)控制反转
- 过使用工厂模式,实现了表现层——业务层——持久层的解耦。
- 它的核心思想就是:
- 通过读取配置文件反射创建对象。
- 把创建出来的对象都存起来,当我们下次使用时可以直接从存储的位置获取。
- 什么是控制反转?
- 把对象的创建交给外部的容器,就是控制反转!
- Inversion of control(IOC)