設計模式--模版模式

設計模式--模版模式

  1. 涉及到的知識點

    • Java 的接口和抽象類信息

      • 一個類只可以繼承另外一個類,但是可以實現(xiàn)多個接口

      • 抽象類中可以定義屬性粟耻,接口中的屬性都被 定義為 public final static 修飾挤忙,屬于常量

      • 接口和抽象類都可以實現(xiàn)邏輯,接口通過default 修飾方法實現(xiàn)戈泼,抽象類通過普通方法實現(xiàn)

      • 接口中的方法默認修飾為 public abstract

      • 抽象方法在子類中都必須被重寫

      • ---別人補充的

        • 抽象類沒有辦法被new大猛,因為有抽象方法沒有實現(xiàn)挽绩。接口相同

        • 抽象類默認修飾為public ,可以使用public 和 protected 修飾

        • 接口中不能含有靜態(tài)代碼塊和靜態(tài)方法驾中,但是抽象類中可以含有

        • 設計層面上,接口是對行為的抽象唠亚,而抽象類是對統(tǒng)一類型東西的抽象(鳥和飛機的例子)

        • 抽象類作為很多子類的父類灶搜,是一種模版的設計。接口定義的是行為規(guī)范前酿,是輻射類設計薪者。接口作用是可以在不修改子類的情況下剿涮,為子類添加公共的方法攻人,接口是不能實現(xiàn)的。

        • 門和告警功能的實現(xiàn)的例子瞬浓。門的open() 和close() 屬性屬于固有功能猿棉,alarm()屬于附加功能萨赁。因此應該做如下試下

          public abstract class Door{
            void open();
            void close();
          }
          
          public interface Alarm{
            void alarm();
          }
          
          public class AlarmDoor extends Door implements Alarm{
            void open();
            void close();
            void alarm();
          }
          
  • default修飾的方法

    在JDK 1.8 中杖爽,接口中新增了default 修飾的方法紫皇,作用和抽象類中的普通方法類似聪铺。在不修改子類實現(xiàn)情況下,修改接口的公共方法撒桨。算是對歷史遺留問題的解決方案。

    調用方式赖阻,可以像調用普通父類方法一樣調用接口中default 修飾的方法

    • 多個接口中包含default 修飾相同的方法火欧,則實現(xiàn)接口的類必須重寫接口中default修飾的方法
    • 如果接口中和父類都含有相同的方法苇侵,接口中用default修飾企锌,那么子類調用時候會使用父類中的方法
    • 接口默認方法增強了Java 8中的Collections API以支持lambda表達式撕攒。

    接口中使用靜態(tài)代碼塊 static

    • 無法被復寫
    • 調用方式為 接口名.function()
  • 泛型 T E ?的區(qū)別

    在JDK 5 中引入的泛型萍鲸,泛型的本質是參數(shù)化類型脊阴。如果不使用泛型嘿期,使用Object 將會使參數(shù)任意化埋合,任意化的結果是對于類型轉換在運行時才可以確定饥悴,可能會出現(xiàn)類型轉化失敗。另外代碼里面需要強制類型轉化瓣铣。

    T E K V ? 都是通配符,一般情況下有如下語義

    • T type E element K key v value
    • ? 表示不確定java類型

    泛型和不確定類型的通配符需要單獨說明

  • for(;;) 的用法 沒有搜索到

  • Obejct...的意思

    Java 中的可變參數(shù)

    • 可變參數(shù)必須放在最后棠笑,所以一個方法只能有一個可變參數(shù)
    • 可變參數(shù)的本質是數(shù)組
    • 可變參數(shù)本身是提供的語法糖蓖救,這個在python中使用非常多,在不確定參數(shù)長度時候可以使用
  • protected的含義

    作為java中權限訪問控制的一個修飾符

    訪問控制的邊界為

    • public 所有類都可以使用
    • producted 子類可以訪問prodected修飾的變量或者方法斩例,或者相同包下的類可以調用
    • Default 基于同包的訪問
    • private 只有當前類可以使用變量或者方法
  1. 模版方法的功能

    定義一個操作中的算法的骨架念赶,而將一些步驟延遲到子類中恰力。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟踩萎。

    個人理解: 模版方法是將一些action,通用的部分寫在父類的抽象類中實現(xiàn),各個子類獨立的部分在各個子類中實現(xiàn)香府。減少不必要的重復又解耦的方案

    如果我們將編程增加可拓展性和調用修改復雜度兩個方面看回还,模版模式就是對這些目的的實現(xiàn)柠硕。

  2. 例子1 运提,JDK中AbstrictList 類使用了模版方法,這里的代碼寫的有點奇怪民泵,在AbstrictList中,add(int index, E e )沒有使用抽象方法栈妆,但是同樣需要子類重寫改方法

    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
         public boolean add(E e) {
            add(size(), e);
            return true;
        }
        
        /** 在AbstrictList中鳞尔,沒有將add(int index, E e );方法作為一個抽象方法寥假,而是定義方法,同時拋出異常枫振。這樣做的效果是
         *  在子類中,如果不重寫這個方法斧拍,編譯器沒有異常杖小,但是在調用父類這個方法時候會拋出異常窍侧。
         *  所以,子類必須重寫這個方法硼啤,實現(xiàn)自己的add邏輯
         */
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
    }
    
    // 子類ArrayList 中斧账,重寫了add(int index, E e ) 這個方法
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
      
      public void add(int index, E element) {
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);
            elementData[index] = element;
            size++;
        }
    }
    
  3. 第二個例子是工作中遇到的嗓袱,需求是做一個混合引擎調度器,在執(zhí)行SQL時候渠抹,可以選擇多種引擎去執(zhí)行梧却,在優(yōu)先選擇的引擎執(zhí)行失敗時候使用其他引擎降級放航。

    使用模版方法的思路是: 每一個引擎執(zhí)行代碼的邏輯大致是相同的圆裕,比如提前清理文件,校驗執(zhí)行結果等赊时。但是具體的執(zhí)行蛋叼,每個引擎各部想不狈涮。

    • 引擎的抽象父類

      public abstract class Engine {
      
          private List<CheckRule> rules;
          private String engineName;
      
          public Engine(String engineName, List<CheckRule> rules) {
              this.rules = rules;
              this.engineName = engineName;
          }
      
          public String getEngineName(){return engineName;}
      
          public List<CheckRule> getRules() {
              return rules;
          }
      
      
          public boolean run(EngineDispatcher dispatcher, String sql, Properties config){
              System.out.println("dear , your task is running...");
              long startTime = System.currentTimeMillis();
              clearDatePath(config.getProperty("dataPath"));
              boolean result = runInternal(sql, config);
              long endTime = System.currentTimeMillis();
              if (! result){
                  return fallBack(dispatcher,config.getProperty("roiginsql"),config);
              }
              return result;
          }
      
          protected void clearDatePath(String dataPath) {
              File file = new File(dataPath);
              try {
                  if(file.exists()){
                      FileWriter fileWriter = new FileWriter(file);
                      fileWriter.write("");
                      fileWriter.flush();
                      fileWriter.close();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          protected abstract boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config);
      
          protected abstract boolean runInternal(String sql, Properties config);
      
          protected abstract void cancel(Properties config);
      
      }
      
      
      
      

      Hiveserver2引擎的實現(xiàn)

      public class Hiveserver2Engine extends Engine {
      
          static final int DEFAULT_QUERERY_TIME_OUT = 10 * 1000;
          HiveStatement stmt = null;
          Connection conn = null;
          public Hiveserver2Engine(String engineName) {
              super(engineName);
          }
      
          @Override
          protected boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config) {
              return false;
          }
      
          @Override
          protected boolean runInternal(String sql, Properties config) {
              //具體的實現(xiàn)邏輯
              return false;
          }
      
          @Override
          protected void cancel(Properties config) {
              
          }
      }
      

      Presto的實現(xiàn)

      public class PrestoJDBCEngine extends Engine {
      
          public PrestoJDBCEngine(String engineName) {
              super(engineName);
          }
      
          @Override
          protected boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config) {
             // 這里需要降級
              return false;
          }
          @Override
          protected boolean runInternal(String sql, Properties config) {
              return runPresto(sql,config);
          }
          @Override
          protected void cancel(Properties config) {
              
          }
      
          private boolean runPresto(String sql , final Properties config){
              return false;
          }    
      }
      
      
 ```java
 public class EngineDispatcher {
 
     public static final String HIVE_SERVER2 = "";
     public static final String PRESTO_JDBC = "";
 
     public static String DEFAULT_ENGINE = HIVE_CLI;
 
     public Map<String, Engine> engines = new LinkedHashMap<String, Engine>();
     private Engine runningEngine;
 
     public EngineDispatcher() {
         engines.put(PRESTO_JDBC, new PrestoJDBCEngine(PRESTO_JDBC));
         engines.put(HIVE_CLI,new HiveCliEngine(HIVE_CLI));
     }
 
     // 選擇引擎的邏輯,這里會有很多條件判斷
     public Map<String,String> dispatch(String sql, Properties config){
         // 分發(fā)和解析sql規(guī)則松却,確定執(zhí)行的引擎
     }
 
     private String dispatchInternal(HiveClient hiveClient,
                                     String selectSql, Properties config) throws SQLException, RuleCheckException, ExplainResultException {
     }
 
     public Engine getRunningEngine() {
         return runningEngine;
     }
 
     public void setRunningEngine(Engine runningEngine) {
         this.runningEngine = runningEngine;
     }
 }
 ```

 真實調用

 ```java
 public class ExecuteSql {
 
   private static Properties config;
   private static EngineDispatcher dispatcher = new EngineDispatcher();
   private static String address = "";
   
   
   public static boolean executeSql() {
     // 返回引擎信息和對應的SQL
     Map<String, String> engineInfo = dispatcher.dispatch(sql, config);
     String engineName = engineInfo.get("engine");
     String convertedSql = engineInfo.get("convertedsql");
     config.setProperty("comment", engineInfo.get("comment"));
     config.setProperty("convertedsql", convertedSql);
     if (engineName.equals(EngineDispatcher.NO_ENGINE)) {
       LOG.info("引擎選擇失敗,執(zhí)行終止!");
       return false;
     }
     LOG.info("自動路由選擇引擎: " + engineName);
     dispatcher.setRunningEngine(dispatcher.engines.get(engineName));
     //這里是真實的調用
     return dispatcher.getRunningEngine().run(dispatcher, convertedSql, config);
   }
   
 }
 ```

參考連接:

https://segmentfault.com/a/1190000038823160

https://blog.csdn.net/wf13265/article/details/79363522

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末歌焦,一起剝皮案震驚了整個濱河市独撇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纷铣,老刑警劉巖搜立,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件槐秧,死亡現(xiàn)場離奇詭異刁标,居然都是意外死亡命雀,警方通過查閱死者的電腦和手機斩箫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門狐血,熙熙樓的掌柜王于貴愁眉苦臉地迎上來易核,“玉大人,你說我怎么就攤上這事缀匕。” “怎么了阔加?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵胜榔,是天一觀的道長夭织。 經(jīng)常有香客問我尊惰,道長纬向,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任琢岩,我火速辦了婚禮担孔,結果婚禮上吃警,老公的妹妹穿的比我還像新娘酌心。我一直安慰自己,他們只是感情好安券,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布鹦筹。 她就那樣靜靜地躺著铐拐,像睡著了一般徘键。 火紅的嫁衣襯著肌膚如雪吹害。 梳的紋絲不亂的頭發(fā)上赠制,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天钟些,我揣著相機與錄音绊谭,去河邊找鬼。 笑死篙耗,一個胖子當著我的面吹牛宗弯,可吹牛的內容都是我干的搂妻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼欲主,長吁一口氣:“原來是場噩夢啊……” “哼邓厕!你這毒婦竟也來了?” 一聲冷哼從身側響起扁瓢,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤详恼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后引几,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昧互,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年伟桅,在試婚紗的時候發(fā)現(xiàn)自己被綠了硅堆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡贿讹,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情面殖,我是刑警寧澤脊僚,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布椿访,位于F島的核電站,受9級特大地震影響猪腕,放射性物質發(fā)生泄漏。R本人自食惡果不足惜脖岛,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一绍在、第九天 我趴在偏房一處隱蔽的房頂上張望偿渡。 院中可真熱鬧,春花似錦留攒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽在旱。三九已至,卻和暖如春登渣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呻顽。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工喉前, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人见咒。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓恃疯,卻偏偏與公主長得像鸳碧,于是被迫代替她去往敵國和親腾仅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容