【「別跟我不會」系列】Java設計模式之策略模式

  • 2019 年 10 月 8 日
  • 筆記

茶餘飯後的IT小知識,不說了,都是乾貨。 —— 23號老闆

0

1

引入

原創:愛吃回鍋肉的瘦子

一直以來,筆主想寫關於設計模式的系列文章與大家進行交流,但礙於自己經驗上尚淺,無法將此講解透徹,鬧了笑話。但千里之行,始於足下,我決定將我自己的工作中我用到的設計模式與大家分享交流,有不妥還望大家指出。

設計模式一種設計開發上的經驗總結,既然是經驗上的總結,那麼實踐是必然的;但他又是一種設計,所以在我們對需求必須得非常了解,對他可能以後出現什麼樣的變化有個預測。此次我打算先從設計模式中的策略模式講起。

0

2

概念

在策略模式中,一個類的行為或其算法可以在運行時更改。這種類型的設計模式屬於行為型模式。

代碼上的設計上大體架構:

1、抽象的行為:

  public interface Behavior {      public void toDo();  }

2、實現抽象行為的兩個類

public class OneBehavior implements Behavior{ @Override public void toDo() { System.out.println("one"); } }

public class TwoBehavior implements Behavior {      @Override      public void toDo() {          System.out.println("two");      }  }

3、定義公有的行為類:

public class DataBase {      protected Behavior behavior;        public DataBase(Behavior behavior) {          this.behavior = behavior;      }
    public void query(){          behavior.toDo();      }
    public void delete(){          System.out.println("delete");      }    }

從上面代碼架構上看,可以看到策略模式的方式本身就是將本身屬於database中的某些方法抽離出來,用接口的方式來抽象方法。既然這樣,那與我們常用的模板模式有什麼區別呢?

為何不將database設計成抽象類,然後將此進行各個子類實現,我們也可以做到不同方法的實現。注意設計模式是結合具體場景而使用的一種經驗模式。

0

3

深入

那麼在什麼樣的場景下使用策略模式,有什麼樣的場景下使用模板模式呢?

我們知道,在對代碼評價有個復用性比較,那麼我們可以假設這樣的一個場景

假設在query方法中 我們目前只有兩種的查詢邏輯方式,但是有9個查詢需要使用,其中有6個是使用相同的query()。這樣的話,在使用模板模式中我們對query()方法要寫6個相同的代碼。的確,我們還可以將這6個中再寫一個父類繼承,此父類再繼承database,但是delete方法中在這6個有三個delete相同呢又或者其中三個delete方法又與前面3個子類相同呢?

這時候我們用模板模式來實現不同的方法是不可行的。必須將方法解耦化,如何解耦呢?將變化的方法抽象成接口,將database依賴於該接口,也就是說我們可以將接口作為屬性給予database。綜上,在筆主看來,策略模式就是將一些多變的方法抽象出來,來增加代碼的復用。

注意點:

1、分析項目中的變化部分與不變部分;

2、多用組合少用繼承;用行為類組合,而不是行為的繼承,更有彈性;

0

4

實戰部分

筆主是主要開發報表功能的,難免牽扯到生成excel。我這邊生成excel有三種方式,poi,easyExcel,以及第三方軟件。他們各個使用方式有不同的劃分。如果想了解Excel是如何使用poi解析的可以看看前面的文章。(如果找不見,可加微信bboyHan索要)

那麼我那時候為啥選擇使用策略模式,是基於什麼樣的考量呢?這裡就開始討論方法論了。剛開始的時候 ,獲取Excel不是那麼複雜, 我只是單純的使用POI方式生成excel,後面由於有性能上要求,就使用上了easyExcel,在後來excel表格複雜化了,為了便於維護就使用上了第三方軟件功能,再後來運營還要求導出pdf。當然了,這些是需求在討論時候就已經確認要分多次迭代了。如果是三張報表,分別用這三個獲取excel方式,那簡單使用mvc模型就差不多解決了。但是筆主面對的是幾百張報表,必須得將此抽離出來所有的導出功能。也就是我設計一個接口 getFile(),三個行為類poi、easyExcel、第三方實現getFile();再寫一個參數基本類,將選擇什麼樣方式導出放在此處,然後在寫一個獲取數據獲取類,並依賴getFile類。代碼如下:

public interface GetFile {      public File toDo();  }
public class PoiFile implements GetFile {      @Override      public File toDo() {          System.out.println("poi");          return new File("poi");      }  }
public class EasyExcelFile implements GetFile {      @Override      public File toDo() {          System.out.println("EasyExcel");          return new File("EasyExcel");      }    }
public class DataBase {      protected GetFile getFile;        public DataBase(GetFile behavior) {          this.getFile = behavior;      }      public void query(){          getFile.toDo();      }      public void delete(){          System.out.println("delete");      }    }
public class TwoData extends DataBase {        public TwoData(GetFile file) {          super(file);      }        @Override      public void query() {          this.getFile.toDo();      }  }
public class OneData extends DataBase{        public OneData(GetFile getFile) {          super(getFile);      }      @Override      public void query() {          this.getFile.toDo();      }  }

參數類:

public class RequestModel implements Serializable {      private String type;        public GetFile getFile(){          if("POI".equalsIgnoreCase(getType()))return new PoiFile();          else return new EasyExcelFile();      }        public String getType() {          return type;      }
    public void setType(String type) {          this.type = type;      }
}

service層:

//交給sring管理DataBase dataBase;  public void query(RequestModel rq){       dataBase.query();  }

0

5

小結

以上就是策略模式實現方式,簡單來說,可以理解為將多變的方法抽離出來,進行解耦合。