模板方法模式

 
定義:定義在一個操做中的一個算法框架,把一些步驟推遲到子類去實現。模板方法模式讓子類不須要改變算法結構而從新定義特定的算法步驟。
    也就是說模板方法定義了一系列算法步驟,子類能夠去實現/覆蓋其中某些步驟,但不能改變這些步驟的執行步驟。
 
模板方法有以下功能:
  • 能解決代碼冗餘問題。
  • 把某些算法步驟延遲到子類,子類能夠根據不一樣狀況改變/實現這些方法,而子類的新方法不會引發以有父類的功能變化。
  • 易於擴展。咱們經過建立新類,實現可定製化的方法就能夠擴展功能。此例中,能夠擴展坐船回家。
  • 父類提供了算法的框架,控制方法執行流程,而子類不能改變算法流程,子類方法的調用由父類模板方法決定。執行步驟的順序有時候很是重要,咱們在容器加載和初始化資源時,爲避免子類執行錯誤的順序,常常使用該模式限定子類方法的調用次序。好比此例中,你不能先回家再買票,也不能先慶祝在回家。
  • 父類能夠把那些重要的、不容許改變的方法屏蔽掉,不讓子類去覆寫(Override/Overwrite)它們,好比在 Java語言中,咱們聲明這些方法爲 final 或者 private 便可。
 
回家過年問題:
package com.guilin.moshi;
 
 
//模板模式(Template Method)
 
public abstract class Guochunjie {
    // 模板方法(框架方法):按照必定順序執行的邏輯
    public void celebrateSpringFestival() {
 
        maipiao();
 
        huijia();
 
        guonian();
    }
 
    // 買票
    protected final void maipiao() {
        System.out.println("買票...");
    }
 
    // 回家(抽象方法)
    protected abstract void huijia();
 
    // 過年
    protected final void guonian() {
        System.out.println("過年...");
    }
}
 
 
class ByFeiji extends Guochunjie {
 
    @Override
    protected void huijia() {
        System.out.println("坐飛機回家...");
    }
}
 
 
class ByHuoche extends Guochunjie {
 
    @Override
    protected void huijia() {
        System.out.println("坐火車回家...");
    }
}
 
// 測試
public class Test {
    public static void main(String[] args) {
        Guochunjie byFeiji = new ByFeiji();
        Guochunjie byHuoche = new ByHuoche();
 
 
        byFeiji.celebrateSpringFestival();
 
        byHuoche.celebrateSpringFestival();
    }
}
使用繼承,子類中不須要實現那些重複的訂票和慶祝團員的代碼,避免了代碼的重複;子類實現了不一樣方式的回家方法,把它栓入(hook)到父類中去,實現了完整的回家過年的邏輯。
 
 
 
 
模板方法模式的應用很普遍,但過度地使用模板方法模式,每每會引發子類的泛濫。爲了解決此問題,一般咱們結合使用回調來處理這種問題。
 
引入回調(Callback)
回調錶示一段可執行的邏輯的引用(或者指針),咱們把該引用(或者指針)傳遞到另一段邏輯(或者方法)裏供這段邏輯適時調用。
回調在不一樣語言有不一樣的實現,例如,在 C語言裏常常使用函數指針實現回調,在 C#語言裏使用代理實現,而在 Java語言裏使用內部匿名類實現回調。
 
查詢數據庫裏的記錄問題:
package  com.guilin.moshi;
import  java.sql.Connection;
import  java.sql.ResultSet;
//泛型
public interface  ResultSetHandler <T > {
      public  T handle(ResultSet rs);
}

class  SimpleJdbcQueryTemplate{
      public   <T > T query(String queryString, ResultSetHandler <T > rsHandler) {
          //...
          try  {
              // 得到一個數據庫的鏈接
            Connection connection =  getCollection ();
              //建立一個 PreparedStatement實例
             stmt   = connection.prepareStatement(queryString);
              //執行該查詢並返回結果
            ResultSet rs =  stmt .executeQuery();
              //調用回調 rsHandler 的 handle(ResultSet  rs )方法來處理查詢結果並返回
              return   rsHandler.handle(rs);
        }   catch ( SQLException  ex) {
              //...
        }   finally  {
              //...
        }
    }
}

public    void  testTemplate() {
      boolean  called =   new  SimpleJdbcQueryTemplate().query( "select * from EMP where NAME = 'GUILIN'" ,
          new  ResultSetHandler <Boolean >() {
             @ Override
              public  Boolean handle(ResultSet rs) {
                  //  TODO  Auto-generated method stub
                  return  Boolean.TRUE;
            }
        }
    );
}
 
咱們使用了 Java的匿名類來回調類處理查詢結果。這樣即便有1千種不一樣的查詢,也不須要增長一個專門的文件。
 
 
 
此模式在 Spring框架裏使用十分普遍,關於 ORM框架和 Jdbc框架的源碼。
 
 
總結:
    爲了解決回家過年的問題,使用了模版方法模式。模版方法模式能夠解決某些場景種的代碼冗餘問題,但也可能引入了類的泛濫問題,結合使用回調避免類的泛濫。同時應該注意若是回調實現的接口較多,代碼較爲複雜時,會引發閱讀問題。
相關文章
相關標籤/搜索