首先写一个jdbc的程序来说明编译器依赖问题
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JdbcDemo1 {
/**
* 程序的耦合
*/
public static void main(String[] args) throws Exception{
//1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy", "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();
}
}
pom添加依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.20</version>
</dependency>
将依赖注释,这段程序会出现错误,并且在编译器不会通过。这就叫做程序的耦合,耦合可以理解为程序间的依赖关系,包括类之间依赖和方法之间的依赖。
解耦就是降低程序间的依赖关系。
实际开发中,应该做到编译器不依赖,运行时才依赖。
解耦思路:
- 使用反射创建对象,避免使用new关键字
- 通过读取配置文件获取要创建的对象全限定类名
分析曾经代码中类似问题
- AccountDao.java
- AccountDaoImpl.java
- AccountService.java
- AccountServiceImpl.java
- Client.java
AccountDao.java
package com.itheima.dao;
/**
* 账户持久层接口
*/
public interface AccountDao {
/**
* 模拟保存账户
*/
void saveAccount();
}
AccountDaoImpl.java
package com.itheima.dao.impl;
import com.itheima.dao.AccountDao;
/**
* 账户持久层实现类
*/
public class AccountDaoImpl implements AccountDao {
public void saveAccount() {
System.out.println("保存了账户");
}
}
AccountService.java
package com.itheima.service;
/**
* 账户业务层的接口
*/
public interface AccountService {
// 模拟保存账户
void saveAccount();
}
AccountServiceImpl.java
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.service.AccountService;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao = new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
}
}
Client.java
package com.itheima.ui;
import com.itheima.service.AccountService;
import com.itheima.service.impl.AccountServiceImpl;
public class Client {
public static void main(String[] args) {
AccountService as = new AccountServiceImpl();
as.saveAccount();
}
}
程序中存在依赖关系:
- AccountService as = new AccountServiceImpl();
- private AccountDao accountDao = new AccountDaoImpl();
工厂模式解耦
BeanFactory.java
package com.itheima.factory;
import java.io.InputStream;
import java.util.Properties;
/**
* 一个创建bean对象的工厂
*
* bean:在计算机英语中,有可重用组件的含义
* javabean:用java语言编写的可重用组件
*
* 它就是创建我们的service和dao对象的
*
* 思路:
* 需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key:value)
* 通过读取配置文件中配置的内容,反射创建对象
* 配置文件可以是xml也可以是properties
*/
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对象
* @param beanName
* @return
*/
public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = props.getProperty(beanName);
System.out.println(beanPath);
bean = Class.forName(beanPath).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return bean;
}
}
bean.properties:
accountService = com.itheima.service.impl.AccountServiceImpl
accountDao = com.itheima.dao.impl.AccountDaoImpl
将之前的两段代码进行修改:
//AccountService as = new AccountServiceImpl();
AccountService as = (AccountService)BeanFactory.getBean("accountService");
//private AccountDao accountDao = new AccountDaoImpl();
private AccountDao accountDao = (AccountDao)BeanFactory.getBean("accountDao");
这样就完成了工厂模式的解耦。
分析工厂模式中的问题并改造
多例模式被创建多次,执行效率没有单例对象高。
单例模式只被创建一次,从而类中的成员也就只会初始化一次。
BeanFactory.java
package com.itheima.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语言编写的可重用组件
*
* 它就是创建我们的service和dao对象的
*
* 思路:
* 需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key:value)
* 通过读取配置文件中配置的内容,反射创建对象
* 配置文件可以是xml也可以是properties
*/
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失败");
}
}
/**
* 根据bean的名称获取对象
* @param beanName
* @return
*/
public static Object getBean(String beanName) {
return beans.get(beanName);
}
/**
* 根据bean名称获取bean对象
* @param beanName
* @return
*
public static Object getBean(String beanName) {
Object bean = null;
try {
String beanPath = props.getProperty(beanName);
// System.out.println(beanPath);
bean = Class.forName(beanPath).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return bean;
}*/
}
Client.java
package com.itheima.ui;
import com.itheima.dao.AccountDao;
import com.itheima.factory.BeanFactory;
import com.itheima.service.AccountService;
import com.itheima.service.impl.AccountServiceImpl;
public class Client {
public static void main(String[] args) {
//AccountService as = new AccountServiceImpl();
for(int i=0; i<5; i++) {
AccountService as = (AccountService