1. 程式人生 > >程式之間耦合以及解耦問題探究

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

之前的一個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,得到就是一個單例物件

相關推薦

程式之間耦合以及問題探究

之前的一個jdbc查詢資料的案例 package com.ithema.jdbc; import java.sql.*;

依賴耦合、控制反轉(IOC)、依賴註入

增加 clas 說明 class a lan xxx ron pen pub 隨著net的深入學習,出現了很多概念性的東西需要理解,現在統一記錄一下。 1.依賴:現階段在任何一個有請求作用的系統,都會出現A類調用B類的情況,這時候A類就依賴於B類,A類和B類存在依賴關系。

什麼是耦合

一、耦合 1、耦合是指兩個或兩個以上的體系或兩種運動形式間通過相互作用而彼此影響以至聯合起來的現象。 2、在軟體工程中,物件之間的耦合度就是物件之間的依賴性。物件之間的耦合越高,維護成本越高,因此物件的設計應使類和構件之間的耦合最小。 3、分類:有軟硬體之間的耦合,還有

案例40-層與層之間(面向接口編程)

sql 獲得 post turn 對象 轉發 詳情 hot axon 1 bean.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans> <!-- 配置AdminServ

mp-redux:程式中的業務與檢視,讓測試更容易

專案地址:點我,歡迎star和issue mp-redux 一個用於小程式和輕量級H5應用的狀態管理工具, 使用方法是一個簡化版本的Redux。之所以是適用於輕量級應用,主要是因為沒有實現元件間的資料共享。因此不適合於複雜,龐大的前端應用。 是否你需要使用它? 如果你也和我有同樣的困惑,那麼你就該嘗試

人工智慧 人臉識別 使用MQ實現以及非同步

從之前的人臉識別的文章來看,使用到mq中間處理的主要在捉拍機獲取到的人臉識別的特徵傳送到rabbitMQ,然後單張人臉註冊的服務進行消費,這時候就是實現了服務之間的非同步處理以及解耦的作用 還有之前的批量處理上傳的人臉特徵的服務,使用的是同步的方式,這種方式確實有點low,需要非同步來處理提

程式的必要性

https://mp.weixin.qq.com/s/6pCJFrNOk4HJYlS5qu4K4A? 架構設計中,大家都不喜歡耦合,但有哪些典型的耦合是我們系統架構設計中經常出現的,又該如何優化?這裡列舉了6個點:IP、jar包、資料庫、服務、訊息、擴容。這些點,如果設計不慎,都會導致系統一些耦

的好處以及哪來的這麼多好處

關於解耦合的一個現例項子: “跟大部分餐飲企業一樣,星巴克也主要致力於將訂單處理的吞吐量最大化。顧客訂單越多,收入就越多。為此,他們採取了非同步處理的辦法。你在點單時,收銀員取出一隻咖啡杯,在上面作上記號表明你點的是什麼,然後把這個杯子放到佇列裡去。這裡

基於retrofit的網路框架的終極封裝(二)-與retrofit的對接與,以及遇到的坑

在上一篇基於retrofit的網路框架的終極封裝(一)中介紹了頂層api的設計.這裡再沿著程式碼走向往裡說. 由於這裡講的是retrofit的封裝性使用,所以一些retrofit基礎性的使用和配置這裡就不講了. 引數怎麼傳遞到retrofit

框架漫談之spring(一)工廠模式實現程式,spring框架的引出

1.程式的耦合度 我們來看如下的程式碼 // 表現層 public class UserController { public static void main(String[] args) { IUserService user

spring Autowired註釋以及如何使用介面物件實現

@Autowired 註釋,它可以對類成員變數、方法及建構函式進行標註,完成自動裝配的工作。 通過 @Autowired的使用來消除 set ,get方法。在使用@Autowired之前,我們對一個bean配置起屬性時,是這用用的 <property name="

基於 SailingEase WinForm Framework 開發優秀的客戶端應用程式(3:實現選單/工具欄按鈕的及狀態控制)

private void InitializeNavigation() { _navigationService.Register("MainMenu://Session[Text='會話']/Session/"); _navi

來點不一樣的: HTML、CSS 和 JS之間的那些事

當前在網際網路上,任何一個稍微複雜的網站或者應用程式都會包含許多HTML、CSS 和 JavaScript。隨著網際網路運用的發展以及我們對它的依賴性日益增加,設定一個關於組織和維護你的前端程式碼的計劃是絕對需要的。 當今的一些大型網際網路公司,由於越來越多的人會接觸到

[Vue 牛刀小試]:第十四章 - 程式設計式導航與實現元件與 Vue Router 之間

 一、前言   在上一章的學習中,通過舉例說明,我們瞭解了 Vue Router 中命名路由、命名檢視的使用方法,以及如何通過 query 查詢引數傳參,或者是採用 param 傳參的方式實現路由間的引數傳遞。通過學習我們可以發現,在實現路由間的引數傳遞時,我們將 Vue Router 與我們的元

Spring中如何使用工廠模式實現程式

目錄 1、 啥是耦合、解耦? 2、 jdbc程式進行解耦 3、傳統dao、service、controller的程式耦合性 4、使用工廠模式實現解耦 5、工廠模式改進 6、結語

程式設計師需要了依賴衝突的原因以及解決方案

0x00. 前言 依賴衝突是日常開發中經常碰到的過程,如果運氣好,並不會有什麼問題。偏偏小黑哥有點背,碰到好幾次生產問題,排查一整晚,最後發現卻是依賴衝突的引起的問題。 沒碰到過這個問題同學可能沒什麼感覺,小黑哥舉兩個最近碰到例子,讓大家感受一些。 例子 1: 我們公司有個古老的業務基礎包 A。B,C 業

模組(類)之間利器:EventPublishSubscribeUtils 事件釋出訂閱工具類

如果熟悉C#語言的小夥伴們一般都會知道委託、事件的好處,只需在某個類中提前定義好公開的委託或事件(委託的特殊表現形式)變數,然後在其它類中就可以很隨意的訂閱該委託或事件,當委託或事件被觸發執行時,會自動通知所有的訂閱者進行消費處理。(觀察者模式用委託來實現是最好不過了,DDD所提倡的事件驅動其根本理念也是如此

簡單的工廠+反射+ xml

logs trace att loader 類加載 一個 encoding saxreader cnblogs 傳統的調用業務層是:   CustomerServiceImpl csi = new CustomerServiceImpl(); 通過面向接口編程改進過後:  

iOS 運行時RunTime使用場景一:打點統計用戶行為,深度

cab else 地址 註入 響應事件 加載失敗 tor top perf 轉自:http://www.jianshu.com/p/0497afdad36d 用戶統計.jpeg 用戶行為統計(User Behavior Statistics, UBS)一直是移

Android學習探索之運用MVP設計模式實現項目

Android 前言: 一直致力於提高開發效率降低項目耦合,今天想抽空學習一下MVP架構設計模式,學習一下如何運用到項目中。 MVP架構設計模式 MVP模式是一種架構設計模式,也是一種經典的界面模式。MVP中的M代表Model, V是View, P是Pre