SpringJava框架

【Spring】 02 - 程序之间的耦合

2020-09-12  本文已影响0人  itlu

1. 案例回顾传统JDBC操作

  1. 注册驱动;
  2. 获取连接 ;
  3. 获取操作数据库的预处理对象;
  4. 执行SQL查询数据库得到结果集;
  5. 遍历结果集;
  6. 释放资源;

1.1 创建一个Maven项目

  1. 在 file -> new - > project 下创建一个maven项目不使用骨架的方式:
创建一个项目使用Maven,但是不使用骨架
  1. 引入相关数据库的依赖,mysql-connector :
 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>
  1. 创建案例中需要使用的数据库和数据:
CREATE DATABASE spring CHARACTER SET utf8;

USE spring;

create table account(
    id int primary key auto_increment,
    name varchar(40),
    money float
)character set utf8 collate utf8_general_ci;

insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);
  1. 编写测试类进行测试 : 代码中 ,如果使用方式二注册驱动,当我们项目中没有了Mysql驱动的jar包的时候是无法通过编译的。
/**
 * @author lyp
 * <p>
 * 传统JDBC 测试类
 */
public class JDBCTest {

    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
             // 1. 注册驱动 方式一
            // Class.forName("com.mysql.jdbc.Driver");

            // 1. 注册驱动 方式二
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            // 2. 获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/spring", "root", "root");

            // 3. 获取操作数据库的预处理对象
            ps = conn.prepareStatement("select * from account");

            // 4. 执行SQL查询数据库得到的结果集
            rs = ps.executeQuery();

            // 5. 遍历结果集
            while (rs.next()) {
                System.out.println(rs.getString("name") + "    ");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
使用方式二注册驱动,当Demo中的Mysql驱动jar包被删除的时候将出现的问题 使用方式一注册Mysql驱动,当Demo中的jar删除后的情况

1.2 程序的耦合

  1. 耦合:程序之间的依赖关系;

  2. 类之间的依赖;

  3. 方法之间的依赖;

  4. 解耦:降低程序之间的依赖关系;

  5. 实际开发中应该做到:

编译期不依赖,运行时才依赖;

  1. 解决类之间的依赖:

第一步:使用反射创建对象,二是避免使用 new 关键字。
第二步:通过读取配置文件来获取需要创建的对象全限定类名。

1.3 传统代码中的问题分析

  1. 创建一个新的项目 。使用Maven但是不使用骨架。

  2. 这是一个模拟zhuanzhang的一个操作:从持久层到表现层。

  3. 创建一个持久层接口并创建一个实现类 :

/**
 * 账户持久层接口
 * @author lyp
 */
public interface AccountDao {

    /**
     * 保存账户信息
     */
    void saveAccount();
}
/**
 * 保存账户信息持久层实现类
 * @author lyp
 */
public class AccountDaoImpl implements AccountDao {
    /**
     * 保存账户信息持久层实现类
     */
    public void saveAccount() {
        System.out.println("保存了账户信息.....");
    }
}
  1. 创建一个业务层接口并创建其实现类 : 其中就会有一个类与类之间的依赖问题。
/**
 * @author lyp
 *
 * 模拟账户业务层接口
 */
public interface AccountService {

    /**
     * 保存账户信息
     */
    void saveAccount();
}

/**
 * AccountService 业务层接口实现类
 * @author lyp
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao  = new AccountDaoImpl();

    public void saveAccount() {
        accountDao.saveAccount();
    }
}
使用了new关键字是程序出现了类与类之间的依赖问题
  1. 创建测试类(代替表现层)Client
/**
 * 测试客户端
 * @author lyp
 */
public class Client {

    public static void main(String[] args) {
        AccountService service = new AccountServiceImpl();
        service.saveAccount();
    }
}
使用new关键字将给程序带来类与类之间的依赖问题
  1. 在以上的程序中,如果我将持久层,或者是业务层的任意一个的代码删除,程序将会出现错误而无法运行。

  2. 该如何解决?

使用工厂模式解耦。

1.4 编写工程类和配置文件

  1. Bean: 在计算机英语中,是可重用组件的含义;

  2. JavaBean:用Java语言编写的可重用组件。JavaBean > 实体类

  3. 创建Bean对象的工厂:

第一个,需要一个配置文件来配置我们的service和dao,配置的内容是唯一标识,全限定类名(key : value)。
第二个,通过读取配置文件配置的内容,反射创建对象。

  1. 多例对象和单例对象的区别 :

单例对象的特点:只创建一次,从而类中的成员只会初始化一次。但是有线程问题。
多例对象的特点:对象被创建多次,造成效率低。执行效率没有单例对象高。

单例和多例对象的区别

1.4.4 工厂模式解耦

  1. 创建一个 Beanfactory 工厂类 ,通过解析配置文件 以及 反射等方式创建对象。

  2. 编写配置文件 : key = value 。

accountService=com.lyp.service.impl.AccountServiceImpl
accountDao=com.lyp.dao.impl.AccountDaoImpl
  1. 编写 BeanFactory 创建单例和多例对象:
/**
 * BeanFactory 使用 BeanFactory 创建对象
 *
 * @author lyp
 */
public class BeanFactory {

    private static Properties props;

    /**
     * 用于存 创建好的 对象键值对
     */
    private static Map<String, Object> beans;

    // 在静态代码块中加载配置文件
    static {
        try {
            props = new Properties();
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            // 初始化beans
            beans = new HashMap<String, Object>();
            // 获取到配置文件中的所有key
            Enumeration keys = props.keys();

            // 循环遍历该枚举类型获取每一个 key 并创建对象
            while (keys.hasMoreElements()) {
                String beanName = keys.nextElement().toString();
                String beanPath = props.getProperty(beanName);;
                Object value = Class.forName(beanPath).newInstance();
                beans.put(beanName, value);
            }

        } catch (Exception e) {
            // 这是一个错误 出现错误程序将不再执行
            throw new ExceptionInInitializerError("初始化配置文件异常!");
        }
    }


    /**
     * 获取需要创建的bean对象
     * 单例的
     * @param className
     * @return
     */
    public static Object getBean(String className) {
        return beans.get(className);
    }


    /**
     * 获取需要的 bean 对象
     * 得到的bean是一个多例的对象
     *
     * @param className
     * @return
     */
    /*public static Object getBean(String className) {

        Object bean = null;

        // 需要获取到配置文件中的属性
        String beanPath = props.getProperty(className);

        try {
            // 每次都会调用默认构造函数创建对象
            bean = Class.forName(beanPath).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bean;
    }*/
}

1.4.5 Demo地址

  1. Demo码云地址 : 实现简单的工厂模式创建单例多例对象
上一篇 下一篇

猜你喜欢

热点阅读