程序之间耦合以及解耦问题探究

以前的一个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里面的依赖包文件的引入java

<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
</dependencies>

当程序正常运行,能够看到是有查询到数据输出mysql

可是当咱们把jdbc的依赖包注销掉sql

<!--<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
</dependencies>-->

程序还会正常查询语句嘛,显示结果以下数据库

在程序编译的初期就显示,这个依赖类不存在,那程序就不能运行,这个就是咱们说的耦合!!简单点来讲就是程序之间的依赖关系架构

耦合主要分为两种:类之间的依赖、方法之间的依赖ide

解耦的含义就是下降程序之间的依赖关系,因此咱们在实际开发中要作到编译期不依赖,运行期才依赖函数

如何解决这个依赖问题?类之间的依赖关系测试

一、在建立对象的时候,使用反射来建立对象,避免使用new关键ui

划线部分就是使用了反射注册驱动,里面的内容只是字符串,不是一个类,可是里面字符串是一个mysql数据库,当之后要换数据库的时候仍是要改驱动spa

二、经过读取配置文件来获取建立对象全限定类名

下面是另一个具体案例

三层架构咱们前面都学过,层与层之间都是相互依赖的关系,ui(视图层)调用service里面的实现方法,service调用dao层持久层里面的方法实现数据的查询,这就使得相互之间的依赖关系很强,缺乏那一个实现方法,程序都不能正常实现,那有什么好的解决方法没???

解决方法1、建立一个BeanFactory,用工厂模式解耦

实现思路

一、须要一个文件来配置咱们的service和dao,配置的内容为:惟一标识=全限定类名(keyvalue)

二、经过读取配置文件中配置的内容来反射建立对象

package com.ithema.jdbc.factory;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

/**
 * 一个Bean对象的工厂
 * Bean在计算机英语中,有可重用组件的含义
 * JavaBean:用Java语言编写的可重用组件
 *       JavaBean>实体类
 * 做用它就是建立咱们使用service和dao对象的
 *
 * 实现方法:
 * 一、须要一个文件来配置咱们的service和dao
 *    配置内容:惟一标识=全限定类名(keyvalue)
 * 二、经过读取配置文件中配置的内容,反射对象
 *
 * 配置文件能够是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对象的
 *
 * 实现方法:
 * 一、须要一个文件来配置咱们的service和dao
 *    配置内容:惟一标识=全限定类名(keyvalue)
 * 二、经过读取配置文件中配置的内容,反射对象
 *
 * 配置文件能够是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,获得就是一个单例对象

相关文章
相关标签/搜索