一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

快速掌握模板方法模式

 田維常 2020-10-30

概述

模板模式就是定義一個(gè)操作中的算法骨架,然后將一些步驟延遲到子類中。模板方法使得子類在不改變算法的結(jié)構(gòu)即可重定義該算法的某些步驟。

使用場(chǎng)景

泡茶

我們都知道泡茶基本步驟有:

燒水、選茶葉、泡茶、喝茶水。

這里指的是一般步驟。至于你燒水時(shí)用什么燒?熱得快、熱水壺、還是其他工具,反正目的是把水燒開就好;你選的茶葉是什么茶葉?鐵觀音、菊花茶、龍井茶等,您想選什么茶喜歡就好;泡茶都是一樣的,就是把茶葉放開水里泡,甚至您也可以選擇自己泡茶時(shí)間的長(zhǎng)久或者選擇水的溫度;至于喝茶是大杯或者還是小杯自己喜歡就好。

API

寫過API接口的碼友們都知道,寫API一般有四個(gè)步驟:

參數(shù)解析、參數(shù)校驗(yàn)、處理業(yè)務(wù)、組織返回參數(shù)。

把請(qǐng)求參數(shù)解析成該業(yè)務(wù)的請(qǐng)求參數(shù)json解析成實(shí)體類;參數(shù)校驗(yàn),您可以使用通用的方式就是判斷參數(shù)是否為空,也可以自己定義特殊的校驗(yàn)方式;處理業(yè)務(wù)一般每個(gè)接口都是不一樣的,基本上都是自己去實(shí)現(xiàn);至于返回參數(shù),可能您得根據(jù)該API接口業(yè)務(wù)來返回。

支付訂單

做過支付相關(guān)的系統(tǒng)的人都清楚,支付訂單大致分這三個(gè)步驟:

組織請(qǐng)求銀行或者第三方支付公司的請(qǐng)求參數(shù)、發(fā)起支付、處理返回結(jié)果。

以上三個(gè)場(chǎng)景中的步驟就是算法骨架,至于每個(gè)步驟可能每個(gè)人喝茶偏好不一樣,API接口業(yè)務(wù)不一樣、銀行或者第三方支付的支付處理不一樣,可能需要自己做特殊的處理。

場(chǎng)景現(xiàn)實(shí)

實(shí)現(xiàn)一個(gè)API接口

算法類
package com.tian.springbootdemo.controller;
import com.tian.springbootdemo.rep.Result;
/**
 * @auther: 老田
 * @Description: 模板類
 */

public abstract class AbstractTemplate {

    /**
     * 算法骨架
     */

    public Result execute() {
        //第一步:解析參數(shù)
        parseRequestParameters();
        //第二步:校驗(yàn)參數(shù)
        checkRequestParameters();
        //第三步:業(yè)務(wù)處理
        Object data= doBusiness();
        //第四步:組織返回參數(shù)
        return assembleResponseParameters(data);
    }

    /**
     * 解析參數(shù)
     */

    public abstract void parseRequestParameters();

    /**
     * 校驗(yàn)參數(shù)
     */

    public abstract void checkRequestParameters();

    /**
     * 業(yè)務(wù)處理
     */

    public abstract Object doBusiness();

    /**
     * 組織返回參數(shù)
     */

    public abstract Result assembleResponseParameters(Object object);
}
實(shí)現(xiàn)類一
import com.tian.springbootdemo.rep.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @auther: 老田
 * @Description: api接口
 */

@RequestMapping("/api")
@Controller
public class MyApiController extends AbstractTemplate {

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    @ResponseBody
    @Override
    public Result execute() {
        return super.execute();
    }

    @Override
    public void parseRequestParameters() {
        System.out.println("*****解析參數(shù)*****");
    }

    @Override
    public void checkRequestParameters() {
        System.out.println("*****校驗(yàn)參數(shù)*****");
    }

    @Override
    public Object doBusiness() {
        System.out.println("*****處理業(yè)務(wù)*****");
        // TODO: 2018/11/17 調(diào)用service處理業(yè)務(wù)
        User user = new User();
        user.setName("小田哥");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }

    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("*****返回參數(shù)*****");
        Result result = new Result("200""處理成功");
        result.setData(object);
        return result;
    }
}
實(shí)現(xiàn)類二
import com.tian.springbootdemo.dao.domain.User;
import com.tian.springbootdemo.rep.Result;
import org.springframework.web.bind.annotation.*;

/**
 * @auther: 老田
 * @Description: api接口
 */

@RequestMapping("/api")
@RestController
public class LoginController extends AbstractTemplate {
    @PostMapping(value = "/login")
    @Override
    public Result execute() {
        return super.execute();
    }
    @Override
    public void parseRequestParameters() {
        System.out.println("解析登錄參數(shù)");
    }

    @Override
    public void checkRequestParameters() {
        System.out.println("校驗(yàn)登錄用戶名是否為空,密碼是否為空");
    }

    @Override
    public Object doBusiness() {
        System.out.println("通過用戶名查詢是否存在此用戶");
        System.out.println("校驗(yàn)用戶密碼是否正確");
        System.out.println("登錄成功");
        User user = new User();
        user.setName("小田哥");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }

    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("*****返回參數(shù)*****");
        Result result = new Result("200""登錄成功");
        result.setData(object);
        return result;
    }
}
相關(guān)類
/**
 * @auther: 老田
 * @Description: 返回信息
 */

public class Result {
    //返回碼
    private String responseCode;
    //描述
    private String message;
    //數(shù)據(jù)
    private Object data;

    public Result() {
    }

    public Result(String responseCode, String message) {
        this.responseCode = responseCode;
        this.message = message;
    }

    public Result(String responseCode, String message, Object data) {
        this.responseCode = responseCode;
        this.message = message;
        this.data = data;
    }

    public String getResponseCode() {
        return responseCode;
    }

    public void setResponseCode(String responseCode) {
        this.responseCode = responseCode;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}
import java.io.Serializable;

/**
 * @auther: 老田
 * @Description: 數(shù)據(jù)
 */

public class User implements Serializable {
    //id
    private Integer id;
    //用戶姓名
    private String name;
    //性別
    private String sex;
    //年齡
    private int age;

    public User() {
    }

    public User(Integer id, String name, String sex, int age) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
測(cè)試

這里使用的是ideaTools下面的REST Client進(jìn)行接口測(cè)試:

enter image description here
enter image description here

再看看控制臺(tái)Console打印出來的信息:

enter image description here

enter image description here

這樣我們就把模板設(shè)計(jì)模式應(yīng)用到我們的具體代碼里了,同樣的我們也可以實(shí)現(xiàn)其他API的實(shí)現(xiàn)類。

另外,參數(shù)校驗(yàn)也可以在 AbstractTemplate  中實(shí)現(xiàn)一個(gè) default   的方式,比如說:校驗(yàn)參數(shù)是否為空,但是子類也可以重寫這個(gè)方法,自己做一個(gè)特殊的校驗(yàn);比如說:如果參數(shù)中有手機(jī)號(hào)碼,那么我們不僅要校驗(yàn)手機(jī)號(hào)是否為空,還可以校驗(yàn)這個(gè)手機(jī)號(hào)碼是不是11位,是否合法的校驗(yàn)等等。

模板模式優(yōu)缺點(diǎn)

優(yōu)點(diǎn)
  • 提高代碼的復(fù)用性,將相同部分的代碼放到抽象類里;

  • 提高拓展性,將不同的放到不同的實(shí)現(xiàn)類里,通過實(shí)現(xiàn)類的擴(kuò)展增加一些自己需要的行為;

  • 實(shí)現(xiàn)反向控制,通過一個(gè)父類調(diào)用實(shí)現(xiàn)類的操作,通過對(duì)實(shí)現(xiàn)類的擴(kuò)展增加新行為,實(shí)現(xiàn)反向控制。

缺點(diǎn)
  • 因?yàn)橐肓顺橄箢悾總€(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類來現(xiàn)實(shí),這樣會(huì)導(dǎo)致類的數(shù)量增多,從而導(dǎo)致系統(tǒng)實(shí)現(xiàn)的復(fù)雜度。

大佬們?cè)诳蚣芾锸窃趺词褂玫模?/span>

Spring中

AbstractApplicationContext 中的refreash方法就是模板方法,源碼為:

@Override
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) { 
            //調(diào)用容器準(zhǔn)備刷新的方法,獲取容器的當(dāng)時(shí)時(shí)間,
            //同時(shí)給容器設(shè)置同步標(biāo)識(shí)
            prepareRefresh();
            //告訴子類啟動(dòng)refreshBeanFactory()方法,
            //Bean定義資源文件的載入從
            //子類的refreshBeanFactory()方法啟動(dòng)
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //為BeanFactory配置容器特性,例如類加載器、事件處理器等
            prepareBeanFactory(beanFactory);
            try { 
                //為容器的某些子類指定特殊的BeanPost事件處理器
                //-----子類實(shí)現(xiàn)
                postProcessBeanFactory(beanFactory);
                //調(diào)用所有注冊(cè)的BeanFactoryPostProcessor的Bean
                invokeBeanFactoryPostProcessors(beanFactory);
                //為BeanFactory注冊(cè)BeanPost事件處理器.
                //BeanPostProcessor是Bean后置處理器,
                //用于監(jiān)聽容器觸發(fā)的事件
                registerBeanPostProcessors(beanFactory);
                //初始化信息源,和國(guó)際化相關(guān).
                initMessageSource();
                //初始化容器事件傳播器.
                initApplicationEventMulticaster();
                //調(diào)用子類的某些特殊Bean初始化方法
                //-----子類實(shí)現(xiàn)
                onRefresh();
                //為事件傳播器注冊(cè)事件監(jiān)聽器.
                registerListeners();
                //初始化所有剩余的單例Bean
                finishBeanFactoryInitialization(beanFactory);
                //初始化容器的生命周期事件處理器,
                //并發(fā)布容器的生命周期事件
                finishRefresh();
                //.....

該方法就是上下文啟動(dòng)模板方法。這就是模板模式在Spring中應(yīng)用場(chǎng)景之一。

Mybatis中

BaseExecutor中的update方法就是一個(gè)模板方法

 /**
     * SqlSession.update/insert/delete會(huì)調(diào)用此方法
     * 模板方法
     */

    @Override
    public int update(MappedStatement ms, Object parameter) throws SQLException {
         ErrorContext.instance().resource(ms.getResource()).activity("executing an                update").object(ms.getId());
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        //先清局部緩存,再更新,如何更新交由子類,
        //模板方法模式
        clearLocalCache();
        //由子類實(shí)現(xiàn)(鉤子方法)
        return doUpdate(ms, parameter);
    }

BaseExecutor里只是定義了方法,但是實(shí)現(xiàn)是在子類里

//更新 
protected abstract int doUpdate(MappedStatement ms, Object parameter)
                                                     throws SQLException
;
//查詢
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds 
                    rowBounds, ResultHandler resultHandler, BoundSql boundSql)

                   throws SQLException
;
 //...do開頭的方法都是交給具體子類自己去實(shí)現(xiàn)

BaseExecutor的實(shí)現(xiàn)類如下:

enter image description here

實(shí)現(xiàn)類SimpleExecutor中的doUpdate方法的實(shí)現(xiàn)

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      //新建一個(gè)StatementHandler
      //這里看到ResultHandler傳入的是null
      StatementHandler handler = configuration.newStatementHandler(
          this, ms, parameter,          RowBounds.DEFAULT, nullnull);
      //準(zhǔn)備語句
      stmt = prepareStatement(handler, ms.getStatementLog());
      //StatementHandler.update
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
}

實(shí)現(xiàn)類ReuseExecutor中的doUpdate方法的實(shí)現(xiàn)

@Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Configuration configuration = ms.getConfiguration();
     //和SimpleExecutor一樣,
     //新建一個(gè)StatementHandler
     //這里看到ResultHandler傳入的是null
     StatementHandler handler = configuration.newStatementHandler(
             this, ms, parameter,       RowBounds.DEFAULT, nullnull);
     //準(zhǔn)備語句
     Statement stmt = prepareStatement(handler, ms.getStatementLog());
     return handler.update(stmt);
  }

這就是Mybatis中的模板方法模式的應(yīng)用。

另外相關(guān)實(shí)現(xiàn)類代碼由于篇幅過了,此處做省略,有興趣的朋友可以聯(lián)系我,咱們一起看源碼。


    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美日韩国内一区二区| 国产成人精品一区二三区在线观看| 成人精品日韩专区在线观看| 91偷拍视频久久精品| 欧美小黄片在线一级观看| 高清一区二区三区四区五区| 日韩一区二区三区嘿嘿| 又黄又色又爽又免费的视频| 欧美精品一区二区三区白虎| 99热九九热这里只有精品| 国产一区日韩二区欧美| 欧美日韩在线视频一区| 国产成人精品一区二三区在线观看 | 欧美亚洲91在线视频| 激情五月天深爱丁香婷婷| 国产精品欧美一区二区三区| 国产精品欧美一区两区| 九九热在线视频精品免费| 国产精欧美一区二区三区久久| 日韩精品日韩激情日韩综合| 午夜福利视频偷拍91| 丰满少妇被猛烈插入在线观看| 成人免费视频免费观看| 亚洲精品偷拍视频免费观看| 午夜亚洲精品理论片在线观看| 一区二区三区精品人妻| 五月婷婷综合激情啪啪| 日本黄色高清视频久久| 91爽人人爽人人插人人爽| 午夜精品麻豆视频91| 福利视频一区二区在线| 亚洲国产色婷婷久久精品| 免费大片黄在线观看国语| 成人精品一区二区三区综合| 91日韩在线观看你懂的| 亚洲黑人精品一区二区欧美| 人妻人妻人人妻人人澡| 国产精品一区二区三区日韩av | 日韩视频在线观看成人| 国产在线一区中文字幕| 国产精品一区二区高潮|