程序的耦合和解耦合
1、程序的耦合:程序间的依赖关系
2、分类:
- 类之间的依赖
- 方法间的依赖
3、解耦合:降低程序间的依赖关系
实际开发中应该做到:编译期不依赖,运行时才依赖。
这里给大家举个例子,我们之前学习的JDBC的过程。OK,看图。
- 过程1:如果用过程1这种方式创建驱动,那么必须拥有com.mysql.cj.jdbc这个实体类,如果你不写,那编译你都通过不了,编译器会直接告诉你错误。这个就是在编译期依赖。
- 过程2:用过程2这种方式,你只需要给类加载器提供一个字段而已,即使你写错了,随便写的,编译的时候也可以过,只不过是运行时期给你抛出异常,但是这个是运行时异常,只在运行时依赖。
解决方式:
第一步:使用反射创建对象,而避免使用new关键字,上面两者的区别,一个依赖具体的驱动类,一个只是依赖字符串而已,就算运行不了也是包没有导入的原因。
第二步:通过读取配置文件来获取要创建的对象的全限定类名,因为像上面这样子写,直接就写死了,后期如果想换其他数据库就不能更改,所以用配置文件来会更加的灵活。
手写Spring的IOC过程
1、控制层
①控制层接口
/**
* 控制层的接口
* */
public interface IAccountService {
/**
* 模拟保存账户
* */
void saveAccount();
}
②控制层实现类
import com.itheima.dao.IAccountDao;
import com.itheima.factory.BeanFactory;
import com.itheima.service.IAccountService;
//账户的控制层实现类
public class AccountServiceImpl implements IAccountService {
//创建Dao层的对象
private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");
public void saveAccount() {
//调用Dao层对象的具体操作方法
accountDao.saveAccount();
}
}
2、Dao层
①Dao层接口
package com.itheima.dao;
//账户Dao层接口
public interface IAccountDao {
void saveAccount();
}
②Dao层实现类
import com.itheima.dao.IAccountDao;
//账户的Dao层实现类
public class AccountDaoImpl implements IAccountDao {
//模拟保存账户,Dao层的具体方法,将来被控制层调用
public void saveAccount() {
System.out.println("保存了账户");
}
}
3、V层
V层实现类
import com.itheima.factory.BeanFactory;
import com.itheima.service.IAccountService;
//模拟一个表现层,用于调用控制层 V层
public class Client {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
IAccountService as = (IAccountService)BeanFactory.getBean("accountService");
System.out.println(as);
}
}
}
4、配置文件
这里我用的配置文件是properties
accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl
5、BeanFactory
/**
* 是一个创建Bean对象的工厂
* Bean:可重用组件
* JavaBean:Java语言编写可重用组件
* JavaBean > 实体类
* Bean工厂就是创建我们的service和dao对象的
*
* */
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props = new Properties();
//获取properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
}
} catch(Exception e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* 根据Bean的名称获取bean对象
* */
public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = props.getProperty(beanName); //根据传的参数获取对应的全限定类名
bean = Class.forName(beanPath).newInstance(); //根据全限定类名创建对应的对象
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
打印结果
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@1540e19d
com.itheima.service.impl.AccountServiceImpl@677327b6
com.itheima.service.impl.AccountServiceImpl@14ae5a5
com.itheima.service.impl.AccountServiceImpl@7f31245a
这里我们拿到的对象都是多例的,而实际中我们想要单例对象,这里我们这样修改。
6、单例模式下的BeanFactory
/**
* 是一个创建Bean对象的工厂
* Bean:可重用组件
* JavaBean:Java语言编写可重用组件
* JavaBean > 实体类
* Bean工厂就是创建我们的service和dao对象的
*
* */
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//定义一个Map容器,用于存放我们要创建的对象,
private static Map<String, Object> beans;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props = new Properties();
//获取properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
//实例化我们的容器
beans = new HashMap<String, Object>();
//取出配置文件中所有的key
Enumeration keys = props.keys();
//遍历枚举
while(keys.hasMoreElements()) {
//取出每个key
String key = keys.nextElement().toString();
//根据key获取value
String beanPath = props.getProperty(key);
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把key和value存入容器中
beans.put(key,value);
}
} catch(Exception e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* 根据名称获取对象
* */
public static Object getBean(String beanName) {
return beans.get(beanName);
}
}
打印结果
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
com.itheima.service.impl.AccountServiceImpl@74a14482
这样我们就拿到了单例对象。