国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從源碼學(xué)習(xí)設(shè)計(jì)模式之模板方法

yankeys / 2832人閱讀

摘要:模板方法模式定義了一個(gè)算法的步驟,并允許子類別為一個(gè)或多個(gè)步驟提供其實(shí)踐方式。在軟件工程中,它是一種軟件設(shè)計(jì)模式,和模板沒(méi)有關(guān)連。模板方法充分運(yùn)用了多態(tài)與繼承。去建設(shè)銀行支付去招商銀行支付實(shí)現(xiàn)模板方法的細(xì)節(jié),我們來(lái)看使用邏輯。

Photo by Tomá? Malík on Unsplash

什么是模板方法模式?摘錄 wiki 的介紹。

模板方法模式定義了一個(gè)算法的步驟,并允許子類別為一個(gè)或多個(gè)步驟提供其實(shí)踐方式。讓子類別在不改變算法架構(gòu)的情況下,重新定義算法中的某些步驟。在軟件工程中,它是一種軟件設(shè)計(jì)模式,和C++模板沒(méi)有關(guān)連。

模板設(shè)計(jì)方法存在目的在于某些算法邏輯存在一些相同處,而具體細(xì)節(jié)卻不同。這樣使用模板方法,可以抽取共用邏輯到父類,在子類實(shí)現(xiàn)具體算法細(xì)節(jié),這樣減少了重復(fù)代碼。
模板方法充分運(yùn)用了多態(tài)與繼承。使用抽象父類定義抽象操作,然后在公共邏輯調(diào)用抽象方法。子類方法只要繼承父類關(guān)注自身實(shí)現(xiàn)細(xì)節(jié)。

Talk is cheap. Show me the code

下面拿支付接入支付渠道例子來(lái)使用模板方法。

假設(shè)銀行卡支付需要實(shí)現(xiàn)兩家銀行的支付功能。不同銀行提供的接口,在參數(shù),調(diào)用方式等肯定存在很大區(qū)別。這個(gè)時(shí)候我們就可以使用模板設(shè)計(jì)方法,父類實(shí)現(xiàn)支付前通用邏輯,用子類實(shí)現(xiàn)交互的不同。系統(tǒng)類結(jié)構(gòu)如下。

AgreementPay 提供支付功能,AgreementBasePay 為抽象類實(shí)現(xiàn)通用邏輯,AgreementCCBPayAgreementCMBPay 實(shí)現(xiàn)具體的渠道支付方法。具體源碼如下。

AgreementPay 接口

public interface AgreementPay {

    PayResponse payInChannel(PayRequest request);
}

AgreementBasePay 抽象方法實(shí)現(xiàn)通用邏輯。

public abstract class AgreementBasePay implements AgreementPay {

    public PayResponse pay(PayRequest request) {
        checkRequest(request);
        return this.payInChannel(request);
    }


    private void checkRequest(PayRequest request) {
        System.out.println("具體方法參數(shù)檢查");
    }
}

具體實(shí)現(xiàn)類,實(shí)現(xiàn)具體渠道支付細(xì)節(jié)。

public class AgreementCCBPay extends AgreementBasePay {
    @Override
    public PayResponse payInChannel(PayRequest request) {
        System.out.println("去建設(shè)銀行支付");
        return new PayResponse();
    }
}

public class AgreementCMBPay extends AgreementBasePay {
    @Override
    public PayResponse payInChannel(PayRequest request) {
        System.out.println("去招商銀行支付");
        return new PayResponse();
    }
}

實(shí)現(xiàn)模板方法的細(xì)節(jié),我們來(lái)看 client 使用邏輯。

public class Client {

    public static void main(String[] args) {
        System.out.println("使用招商銀行支付");
        AgreementPay agreementPay = new AgreementCMBPay();
        PayRequest request = new PayRequest();
        agreementPay.payInChannel(request);
        System.out.println("使用建設(shè)銀行支付");
        agreementPay = new AgreementCCBPay();
        agreementPay.payInChannel(request);
    }
}

上面 client 邏輯,其實(shí)看起來(lái)還是有一些死板,且需要外部知道調(diào)用哪個(gè)渠道接口。但是如果真正提供一個(gè)對(duì)外接口,外部調(diào)用方法是不關(guān)心你具體使用那個(gè)子類支付。所以這里我們可以改進(jìn)一下,

    public static Map payCache = new HashMap<>();

    static {
        payCache.put("CMB", new AgreementCMBPay());
        payCache.put("CCB", new AgreementCCBPay());
    }


    public static void main(String[] args) {
        PayRequest request = new PayRequest();
        AgreementPay pa;
        switch (request.getBankCode()) {
            case "CMB":
                pa = payCache.get("CMB");
                pa.payInChannel(request);
                return;
            case "CCB":
                pa = payCache.get("CCB");
                pa.payInChannel(request);
                return;
            default:
                throw new RuntimeException();
        }

    }

改造之后我們先將其 AgreementPay 實(shí)例放入 map 中,然后調(diào)用時(shí)根據(jù)一個(gè)標(biāo)志來(lái)選擇具體實(shí)現(xiàn)類。

從上面的細(xì)節(jié)我們可以看到模板方法其實(shí)設(shè)計(jì)思路與實(shí)現(xiàn)細(xì)節(jié)都比較簡(jiǎn)單??赐晡覀兊氖纠a,我們?nèi)タ聪?mybatis 如何使用模板方法。

mybatis 模板方法應(yīng)用

在看源碼之前,我們先看下我們不使用 mybatis 之前,如何查詢數(shù)據(jù)。

        Class.forName("com.mysql.jdbc.Driver");
        //2.獲得數(shù)據(jù)庫(kù)的連接
        Connection conn = DriverManager.getConnection(URL, NAME, PASSWORD);
        //3.通過(guò)數(shù)據(jù)庫(kù)的連接操作數(shù)據(jù)庫(kù),實(shí)現(xiàn)增刪改查
        PreparedStatement pstmt = conn.prepareStatement("select user_name,age from imooc_goddess where id=?");
        pstmt.setInt(1, 21);
        ResultSet rs = pstmt.execute();
        
        while (rs.next()) {//如果對(duì)象中有數(shù)據(jù),就會(huì)循環(huán)打印出來(lái)
            System.out.println(rs.getString("user_name") + "," + rs.getInt("age"));
        }

我們可以看到直接使用 JDBC 查詢,十分麻煩,且需要我們自己將 java 類型轉(zhuǎn)換成 jdbc 數(shù)據(jù)類型。

ORM 框架重要作用在于把數(shù)據(jù)庫(kù)表與 java,ORM 框架省去我們自己將 java 類型轉(zhuǎn)化成 JDBC 類型的麻煩。JDBC 存在有那么多類型,如何做到轉(zhuǎn)換的那?其實(shí)關(guān)鍵就是應(yīng)用模板設(shè)計(jì)方法。

mybatis 中存在一個(gè)接口 TypeHandler,該接口方法主要如下:

public interface TypeHandler {

  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

從方法上看,這個(gè)接口主要的方法為 PreparedStatement 設(shè)置列參數(shù),或者從 ResultSet 獲取列的值然后轉(zhuǎn)換成相應(yīng)的 java 數(shù)據(jù)類型。我們看下這個(gè)接口實(shí)現(xiàn)的類圖。

可以看到 BaseTypeHandlerTypeHandler 的具體抽象類,我們具體看下 TypeHandler getResult 在抽象類中實(shí)現(xiàn)細(xì)節(jié)。

  @Override
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    T result;
    try {
      result = getNullableResult(rs, columnName);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column "" + columnName + "" from result set.  Cause: " + e, e);
    }
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

   public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

可以看到其最后調(diào)用抽象方法 getNullableResult。其由具體的子類的實(shí)現(xiàn)。我們具體找一個(gè)子類 DateTypeHandler 來(lái)查看具體實(shí)現(xiàn)。

public class DateTypeHandler extends BaseTypeHandler {


    // 忽略其他方法
  @Override
  public Date getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    Timestamp sqlTimestamp = rs.getTimestamp(columnName);
    if (sqlTimestamp != null) {
      return new Date(sqlTimestamp.getTime());
    }
    return null;
  }

}

可見(jiàn)其具體從 ResultSet 取出 JDBC 類型為 Timestamp,然后轉(zhuǎn)換成 java 類型的 Date

實(shí)現(xiàn)具體的子類,那么在哪里使用了那?其實(shí) mybatis 框架會(huì)把所有 TypeHandler 在 TypeHandlerRegistry 注冊(cè)。具體類方法如圖

。

其提供了相關(guān) register 方法注冊(cè) TypeHandler,然后又提供了相關(guān) getTypeHandler 方法取出具體 TypeHandler 實(shí)現(xiàn)類。

總結(jié)

使用模板方法,將公共邏輯抽取出來(lái),將具體實(shí)現(xiàn)細(xì)節(jié)交給子類。

參考

Mybatis源代碼分析之類型轉(zhuǎn)換

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/72794.html

相關(guān)文章

  • 源碼分析 @angular/cdk Portal

    摘要:這些依賴對(duì)象也進(jìn)一步暴露了其設(shè)計(jì)思想。關(guān)鍵功能包括在上下文內(nèi)掛載在上下文外掛載在上下文外共享數(shù)據(jù)。在構(gòu)造必須依賴,所以可以直接創(chuàng)建嵌入視圖,然后手動(dòng)強(qiáng)制執(zhí)行變更檢測(cè)。提供了兩個(gè)指令和。 @angular/material 是 Angular 官方根據(jù) Material Design 設(shè)計(jì)語(yǔ)言提供的 UI 庫(kù),開(kāi)發(fā)人員在開(kāi)發(fā) UI 庫(kù)時(shí)發(fā)現(xiàn)很多 UI 組件有著共同的邏輯,所以他們把這些共...

    BearyChat 評(píng)論0 收藏0
  • Codeigniter 4.0-dev 版源碼學(xué)習(xí)筆記七—— View 視圖

    摘要:行處理視圖文件名后綴。結(jié)語(yǔ)從源碼上看,使用了原始作為模版機(jī)制使得視圖邏輯非常簡(jiǎn)單。無(wú)非也就是把視圖進(jìn)來(lái),用輸出緩沖把執(zhí)行結(jié)果拿到即可。此文可以轉(zhuǎn)載,但轉(zhuǎn)載前需要發(fā)郵件到進(jìn)行溝通,未溝通的均視作侵權(quán)。 前言 CI 的 View 沒(méi)有像 Laravel 等一些流行框架一樣設(shè)計(jì)的那么重,有自己的一套模版機(jī)制,CI 一直采用純天然的 PHP 模板形式,純天然的好處是不用再學(xué)習(xí)一套模板語(yǔ)言了,缺...

    LiangJ 評(píng)論0 收藏0
  • Bootstrap Metronic 模板學(xué)習(xí)路 - (3)源碼分析 body 部分

    摘要:的組成結(jié)構(gòu)部分包含了,其中部分又包含了幾個(gè)部分。代碼如下圖內(nèi)容展示截圖代碼截圖快捷欄展示截圖代碼截圖頁(yè)面底部展示截圖代碼截圖上一篇之模板的學(xué)習(xí)之路源碼分析之部分下一篇之模板的學(xué)習(xí)之路源碼分析之腳本部分 body 的組成結(jié)構(gòu) body 部分包含了 HEADER、CONTAINER、FOOTER,其中 CONTAINER 部分又包含了 SIDEBAR、CONTENT、QUICK SIDEB...

    afishhhhh 評(píng)論0 收藏0
  • JavaScript 進(jìn)階深入理解數(shù)據(jù)雙向綁定

    摘要:當(dāng)我們的視圖和數(shù)據(jù)任何一方發(fā)生變化的時(shí)候,我們希望能夠通知對(duì)方也更新,這就是所謂的數(shù)據(jù)雙向綁定。返回值返回傳入函數(shù)的對(duì)象,即第一個(gè)參數(shù)該方法重點(diǎn)是描述,對(duì)象里目前存在的屬性描述符有兩種主要形式數(shù)據(jù)描述符和存取描述符。 前言 談起當(dāng)前前端最熱門的 js 框架,必少不了 Vue、React、Angular,對(duì)于大多數(shù)人來(lái)說(shuō),我們更多的是在使用框架,對(duì)于框架解決痛點(diǎn)背后使用的基本原理往往關(guān)注...

    sarva 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<