程序之間耦合以及解耦問題探究

以前的一個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,獲得就是一個單例對象

相關文章
相關標籤/搜索