1. 程式人生 > 其它 >設計模式之靜態工廠方法

設計模式之靜態工廠方法

靜態工廠方法

設計模式

靜態工廠方法

介紹

  • 什麼是靜態工廠方法

    • 通過類內部的靜態方法建立物件而非new

      public static void main(String[] args) {
          Calendar date = Calendar.getInstance();
          
          Integer a = Integer.valueOf(4);
      }
      // 可以看到通過Calendar的靜態方法 getInstance() 就獲得了一個 Calendar 物件
      
  • 透過現象看本質

    • 檢視原始碼

      // 以較為簡單的Integer為例
      public static Integer valueOf(int i) {
          if (i >= IntegerCache.low && i <= IntegerCache.high)
              return IntegerCache.cache[i + (-IntegerCache.low)];
          return new Integer(i);
      }
      public Integer(int value) {
          this.value = value;
      }
      
      • 可以看到呼叫了valueOf方法實際上還是使用了構造方法來進行實現

優勢

  • 我們看到實際上我們使用靜態工廠方法可能最後也是呼叫了構造方法,那麼這種設計模式
    1. 對於某一個類,擁有多個引數的構造方法可能會導致呼叫的時候難以區分,使用靜態工廠方法做一次轉發可以讓每一個構造方法擁有自己的名字

    2. 對於外部呼叫,有時候只是需要一個物件,並不需要直到這個物件是不是一個全新的例項,又或者是我們想對外提供一個單例時,如果使用工廠方法,就可以在內部預先進行判斷,防止建立不必要的物件,減少記憶體開銷

    3. 如果我們直接呼叫構造方法,那麼必然返回的是該類的構造方法的,但是實際上我們可以在靜態工廠方法裡返回該類子類的物件,達到多型的效果

    4. 可以有多個引數相同但名稱不同的靜態工廠方法

      class Goods {
          int weight;
          int price;
          // 假如此時有兩種商品
          // 一種需要論斤賣,那麼它的重量必然是後面稱出來的,所以只需要單價就好了
          // 那麼建立這種商品的構造方法
          public Goods(int price) {
              this.price = price;
          }
      
          // 另一種商品不需要單價, 按照10塊錢一斤稱的, 那麼就需要使用所有商品重量相加
          // 那麼建立這種商品的構造方法
          // public Goods(int weight) {
          //     this.weight = weight;
          // }
          // 構造方法只能區分不同型別不同數量,對於兩個都是int引數就不能區分,所以需要別的辦法解決
      }
      
      class Goods {
          int weight;
          int price;
      
          public Goods(int weight, int price) {
              this.weight = weight;
              this.price = price;
          }
      
          // 一種商品只需要重量
          public Goods goodsWithWeight(int weight){
              return new Goods(weight, 0);
          }
      
          // 一種商品只需要單價
          public Goods goodsWithPrice(int price){
              return new Goods(0, price);
          }
      }
      
    5. 靜態工廠方法可以減少內部程式碼對外暴露的可能性

      class PersonDemo {
          // 有時我們利用引數範圍進行取值,但是如果直接在構造方法裡面進行if判斷
          // 可能會讓程式碼看起來非常亂,而且可能會傳入一些不正確的值導致報錯
          // 利用靜態工廠方法進行提前的篩選判定
          String gender;
          public PersonDemo(String gender) {
              this.gender = gender;
          }
      
          public PersonDemo setAge(int age){
              if (age >=0 && age < 18){
                  return new PersonDemo("未成年");
              } else if (age >= 18 && age < 120){
                  return new PersonDemo("成年人");
              } else {
                  throw new RuntimeException("年齡不正確");
              }
          }
      }
      

總結

  • 我個人覺得靜態工廠方法的意義在於能夠增加類的擴充套件性和限制類的引用方向,在最大程度上能夠指導類的呼叫者的行為,減少對方犯錯誤的機會