之前的一个jdbc查询数据的案例
package com.ithema.jdbc;
import java.sql.*;
/**
* 程序耦合
*/
public class JdbcDemo1 {
public static void main(String[] args) {
try {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/fresh","root","root");
PreparedStatement pstm=conn.prepareStatement("select * from usertable");
ResultSet rs=pstm.executeQuery();
while (rs.next()){
System.out.println(rs.getString("username"));
}
rs.close();
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
下面是pom里面的依赖包文件的引入
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
当程序正常运行,可以看到是有查询到数据输出
但是当我们把jdbc的依赖包注销掉
<!--<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>-->
程序还会正常查询语句嘛,显示结果如下
在程序编译的初期就显示,这个依赖类不存在,那程序就不能运行,这个就是我们说的耦合!!简单点来说就是程序之间的依赖关系
耦合主要分为两种:类之间的依赖、方法之间的依赖
解耦的含义就是降低程序之间的依赖关系,所以我们在实际开发中要做到编译期不依赖,运行期才依赖
如何解决这个依赖问题?类之间的依赖关系
1、在创建对象的时候,使用反射来创建对象,避免使用new关键
划线部分就是使用了反射注册驱动,里面的内容只是字符串,不是一个类,但是里面字符串是一个mysql数据库,当以后要换数据库的时候还是要改驱动
2、通过读取配置文件来获取创建对象全限定类名
下面是另外一个具体案例
三层架构我们前面都学过,层与层之间都是相互依赖的关系,ui(视图层)调用service里面的实现方法,service调用dao层持久层里面的方法实现数据的查询,这就使得相互之间的依赖关系很强,缺少那一个实现方法,程序都不能正常实现,那有什么好的解决方法没???
解决方法一、创建一个BeanFactory,用工厂模式解耦
实现思路
1、需要一个文件来配置我们的service和dao,配置的内容为:唯一标识=全限定类名(keyvalue)
2、通过读取配置文件中配置的内容来反射创建对象
package com.ithema.jdbc.factory;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
/**
* 一个Bean对象的工厂
* Bean在计算机英语中,有可重用组件的含义
* JavaBean:用Java语言编写的可重用组件
* JavaBean>实体类
* 作用它就是创建我们使用service和dao对象的
*
* 实现方法:
* 1、需要一个文件来配置我们的service和dao
* 配置内容:唯一标识=全限定类名(keyvalue)
* 2、通过读取配置文件中配置的内容,反射对象
*
* 配置文件可以是properties或者是xml
*/
public class Beanfactory {
//定义一个properties对象
private static Properties props;
//使用静态代码块创建Properites对象
static {
try {
//实例化对象
props=new Properties();
//获取properites流对象
InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
}catch (Exception e){
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* 根据bean的名称获取bean对象
* @param beanName
* @return
*/
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;
}
}
properites配置文件内容
#全限定类名
accountService=com.ithema.jdbc.service.impl.AccountServiceImpl
accountDao=com.ithema.jdbc.dao.impl.AccountDaoImpl
package com.ithema.jdbc.service;
/**
* 账户业务层的接口
*/
public interface IAccountService {
/**
* 模拟保存账户
*/
void saveAccount();
}
package com.ithema.jdbc.service.impl;
import com.ithema.jdbc.dao.IAccountDao;
import com.ithema.jdbc.dao.impl.AccountDaoImpl;
import com.ithema.jdbc.factory.Beanfactory;
import com.ithema.jdbc.service.IAccountService;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {
//private IAccountDao accountDao=new AccountDaoImpl();
private IAccountDao accountDao= (IAccountDao) Beanfactory.getBean("accountDao");
public void saveAccount(){
accountDao.saveAccount();
};
}
package com.ithema.jdbc.dao;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
void saveAccount();
}
package com.ithema.jdbc.dao.impl;
import com.ithema.jdbc.dao.IAccountDao;
/**
* 账户持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {
@Override
public void saveAccount() {
System.out.println("保存了账户!!");
}
}
测试类实现代码,测试结果如下
package com.ithema.jdbc.ui;
import com.ithema.jdbc.factory.Beanfactory;
import com.ithema.jdbc.service.IAccountService;
import com.ithema.jdbc.service.impl.AccountServiceImpl;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args) {
//IAccountService as=new AccountServiceImpl();
IAccountService as=(IAccountService) Beanfactory.getBean("accountService");
as.saveAccount();
}
}
但是用工厂模式解耦依然存在问题,当在test多次创建对象时候结果如下
package com.ithema.jdbc.ui;
import com.ithema.jdbc.factory.Beanfactory;
import com.ithema.jdbc.service.IAccountService;
import com.ithema.jdbc.service.impl.AccountServiceImpl;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args) {
//IAccountService as=new AccountServiceImpl();
for (int i=0;i<5;i++){
IAccountService as=(IAccountService) Beanfactory.getBean("accountService");
System.out.println(as);
}
//as.saveAccount();
}
}
每次调用构造函数都会创建一个对象,打印出来的是多例对象,那么单例对象和多例对象有什么区别???
多例每次初始化都会创建一个对象,这样的话就会出现线程问题,每次获取到的对象都是不一样的,而我们在servlet和dao层中一般都是采用单例模式
造成创建多例对象的原因
那么有什么办法能解决这个问题嘛??那就是创建一个Map集合来保存反射创建出来的对象
package com.ithema.jdbc.factory;
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对象的
*
* 实现方法:
* 1、需要一个文件来配置我们的service和dao
* 配置内容:唯一标识=全限定类名(keyvalue)
* 2、通过读取配置文件中配置的内容,反射对象
*
* 配置文件可以是properties或者是xml
*/
public class Beanfactory {
//定义一个properties对象
private static Properties props;
//定义一个Map,用于存放我们创建的对象,我们把它称之为容器
private static Map<String,Object> beans;
//使用静态代码块创建Properites对象
static {
try {
//实例化对象
props=new Properties();
//获取properites流对象
InputStream in=Beanfactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
//实例化容器
beans=new HashMap<String,Object>();
//取出配置文件中所有的key
Enumeration keys=props.keys();
while (keys.hasMoreElements()){
String key=keys.nextElement().toString();
//获取value值
String beanPath=props.getProperty(key);
//创建反射对象
Object value=Class.forName(beanPath).newInstance();
//保存到容器中
beans.put(key,value);
}
}catch (Exception e){
throw new ExceptionInInitializerError("初始化properties失败");
}
}
/**
* 根据bean的名称获取bean对象
* @param beanName
* @return
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}
/* 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;
}*/
}
再次运行test类Client,得到就是一个单例对象