程序的耦合及解耦
耦合:程序间的依赖关系
包括:类之间的依赖,方法间的依赖
解耦:降低程序间的依赖关系
实际开发中:
应该做到:编译器不依赖,运行期才依赖
解耦的思路:
第一步:使用反射来创建对象
第二步:通过读取配置文件来获取要创建的对象全限定类名
1、思考一下web项目的框架结构,调用关系(service里面的方法和dao里面的方法定义)
servlet调用service里面的方法,service的接口实现类里面实现service接口中定义的方法,并且实现的时候会调用dao层的一些方法。
相当于service里面定义了一个大方法,dao定义了一个小方法,大方法的实现需要调用小方法
2、复习反射
//Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(对应第一阶段源代码阶段)
//多用于配置文件,将类名定义在配置文件中。读取文件,加载类
//Class对象的newInstance方法,创建对象
bean=Class.forName(beanPath).newInstance();//每次都会调用默认的构造函数创建对象
工厂模式解耦
在原来的写法中:
在service的实现类里要调用dao的方法,必须要先创建dao的实现类对象
例如:
AccountDao accountDao=new AccountDaoImpl();
这样如果dao的实现类不见了,service的实现类就会报错。耦合性太高,为了降低耦合性,我们可以使用配置文件,通过读取配置文件来实现接口实现类对象的创建
引入配置文件后:
AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
配置文件:
配置文件其实是一个双列集合,以key-value的形式存在,可以通过key来获得value (props.getProperty(beanName)),相当于map集合中的get(key)
accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl
利用工厂进行解耦代码:
package com.itheima.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/*
* 一个创建Bean对象的工厂
* Bean:在计算机英语中,有可重复组件的含义
* JavaBean:用Java语言编写的可重复组件
* javabean > 实体类
* 他就是创建我们的service和dao对象的
*
* 第一个,需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个,通过读取配置文件中配置的内容,反射创建对象
*
* 配置文件可以是xml或者properties(解析读取比xml较容易)
*
* */
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//定义一个Map,用于存放我们要创建的对象,我们把它称之为容器
private static Map<String,Object> beans;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props=new Properties();
//获取properties文件的流对象
/*
* 这个地方注意路径的写法:
* 使用类加载器,BeanFactory.class是获取当前对象的Class对象
* getClassLoader()是获取Class对象的类加载器
* getResourceAsStream("Bean.properties"):调用类加载器的方法加载资源,返回的是字节流
* */
InputStream in=BeanFactory.class.getClassLoader().getResourceAsStream("Bean.properties");//每次都会调用默认构造函数创建对象
props.load(in);
//实例化容器
beans=new HashMap<String, Object>();
//取出配置文件中所有的key
Enumeration<Object> 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失败");
}
}
/*根据Bean的名称获取bean对象*/
public static Object getBean(String beanName){
return beanName;
}
/*根据Bean的名称获取bean对象*//*
public static Object getBean(String beanName){
Object bean=null;
try {
String beanPath=props.getProperty(beanName);
//Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(对应第一阶段源代码阶段)
//多用于配置文件,将类名定义在配置文件中。读取文件,加载类
//Class对象的newInstance方法,创建对象
bean=Class.forName(beanPath).newInstance();//每次都会调用默认的构造函数创建对象
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}*/
}
知识点:
1、Bean:在计算机英语中,有可重复组件的含义
* JavaBean:用Java语言编写的可重复组件
* javabean > 实体类
* 他就是创建我们的service和dao对象的
*
* 第一个,需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个,通过读取配置文件中配置的内容,反射创建对象
*
* 配置文件可以是xml或者properties(解析读取比xml较容易)
2、获取properties文件的流对象
* 这个地方注意路径的写法:
* 使用类加载器,BeanFactory.class是获取当前对象的Class对象
* getClassLoader()是获取Class对象的类加载器
* getResourceAsStream("Bean.properties"):调用类加载器的方法加载资源,返回的是字节流
InputStream in=BeanFactory.class.getClassLoader().getResourceAsStream("Bean.properties");//每次都会调用默认构造函数创建对象
3、 如何利用反射创建对象:
*Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
*多用于配置文件,将类名定义在配置文件中。读取文件,加载类
*Class对象的newInstance方法,创建对象
bean=Class.forName(beanPath).newInstance();//每次都会调用默认的构造函数创建对象
多例对象和单例对象的区别: