日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

【Effective Java】第二章:静态工厂、构建器、强化Singleton属性、私有构造器、

發布時間:2024/7/23 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Effective Java】第二章:静态工厂、构建器、强化Singleton属性、私有构造器、 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 一. 用靜態工廠方法代替構造器
      • 優勢:
      • 劣勢:
      • 實例代碼:
  • 二. 遇到多個構造器參數時要考慮使用構建器
      • ① 重疊構建器
      • ② JavaBeans模式
      • ③ Builder模式
  • 三. 用私有構造器或枚舉類型強化Singleton屬性
      • 方法一:公有靜態成員是個final域
      • 方法二:公有的成員是個靜態工廠
      • 方法三:一個包含單個元素的枚舉類型
  • 四. 通過私有構造器強化不可實例化的能力

一. 用靜態工廠方法代替構造器

優勢:

  • 有名稱,可以確切地描述正被返回的對象。
  • 不必在每次調用的時候都創建新對象
  • 可以返回原返回類型的任何子類型對象
  • 返回的對象的類可以隨著每次調用而產生變化。
  • 返回的對象所屬的類,在編寫靜態工廠方法時可以不存在。

劣勢:

  • 類如果不含公有的或者受保護的構造器,就不能被子類化。
  • 程序員很難發現他們,但是可以通過遵守標準的命名習慣來彌補。

實例代碼:

這是第二版的代碼,在第三版里已經刪去了。不過可以用來便于理解。

// 英文部分可以不看,或者作為參考。/** 用于描述Provider所提供的服務 */ public interface Service { ... // Service-specific methods go here } /** 用于描述Provider,每個Provider都要有自己的newService */ public interface Provider { Service newService(); } // Noninstantiable class for service registration and access public class Services { // 私有化構造方法,不會把工廠實例化,直接用類名。 private Services() { } // Prevents instantiation (Item 4)// 使用Map來存儲各provider及其name的映射。 // 使用final:只是providers一直指向當前HashMap,對HashMap里的內容變化沒有影響。 // Maps service names to services private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>(); public static final String DEFAULT_PROVIDER_NAME = "<def>"; ITEM 1: CONSIDER STATIC FACTORY METHODS INSTEAD OF CONSTRUCTORS 9 // Provider registration API public static void registerDefaultProvider(Provider p) { registerProvider(DEFAULT_PROVIDER_NAME, p); } // 注冊Provider到工廠Services里。 public static void registerProvider(String name, Provider p){ providers.put(name, p); } // Service access API public static Service newInstance() { return newInstance(DEFAULT_PROVIDER_NAME); } // 根據name從工廠中取出對應Provider提供的服務。 public static Service newInstance(String name) { Provider p = providers.get(name); if (p == null) throw new IllegalArgumentException( "No provider registered with name: " + name); return p.newService(); } }

二. 遇到多個構造器參數時要考慮使用構建器

① 重疊構建器

參考下面的代碼,活用this,但是參數多的時候難寫,并且用起來容易出錯。

public class NutritionFacts { private final int servingSize; // (mL) required private final int servings; // (per container) required private final int calories; // optional private final int fat; // (g) optional private final int sodium; // (mg) optional private final int carbohydrate; // (g) optional public NutritionFacts(int servingSize, int servings) { this(servingSize, servings, 0); } public NutritionFacts(int servingSize, int servings, int calories) { this(servingSize, servings, calories, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat) { this(servingSize, servings, calories, fat, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) { this(servingSize, servings, calories, fat, sodium, 0); } 12 CHAPTER 2 CREATING AND DESTROYING OBJECTS public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) { this.servingSize = servingSize; this.servings = servings; this.calories = calories; this.fat = fat; this.sodium = sodium; this.carbohydrate = carbohydrate; } }

② JavaBeans模式

  • 構造函數就是:ClassName(){}
  • 賦值交給Setters來實現
  • 彌補了重疊構造器的不足,容易創建實例,并且易讀
  • 缺點1:構造過程中JavaBean可能處于不一致的狀態(畢竟要多次賦值)
  • 缺點2:使得把類做成不可變的可能性不存在(不能final,畢竟之后還要set的嘛)
public class NutritionFacts { // Parameters initialized to default values (if any) private int servingSize = -1; // Required; no default value private int servings = -1; // " " " " private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public NutritionFacts() { } ITEM 2: CONSIDER A BUILDER WHEN FACED WITH MANY CONSTRUCTOR PARAMETERS 13 // Setters public void setServingSize(int val) { servingSize = val; } public void setServings(int val) { servings = val; } public void setCalories(int val) { calories = val; } public void setFat(int val) { fat = val; } public void setSodium(int val) { sodium = val; } public void setCarbohydrate(int val) { carbohydrate = val; } }

③ Builder模式

  • 既保證了像重疊構造器的安全性,也保證像JavaBeans的可讀性
  • 描述:用類的Builder,來構建類的對象。
// Builder Pattern public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; // 在構造函數前,先寫好內部類Builder public static class Builder { // Required parameters private final int servingSize; private final int servings; // Optional parameters - initialized to default values // 與類的final不同,此處因為要用setters,因此不設為final。 private int calories = 0; private int fat = 0; private int carbohydrate = 0; private int sodium = 0; public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } // 逐個屬性設定值,每次都return this:和之后的具體調用相關 public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public Builder sodium(int val) { sodium = val; return this; } // build():使用this builder作為參數來構造類的對象。 public NutritionFacts build() { return new NutritionFacts(this); } } // 私有的構造函數,使用已經完全初始化的builder來進行唯一的一次初始化。 private NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } }
  • 還適用于類層次結構(這里會麻煩點,涉及到抽象類、范式等等)
// 先來個抽象的父類Pizza! // Builder pattern for class hierarchies public abstract class Pizza { public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE } final Set<Topping> toppings; // Builder也是抽象的,這里用到T進行一個約束:只能是Pizza.Builder的字類 abstract static class Builder<T extends Builder<T>> { EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class); public T addTopping(Topping topping) { toppings.add(Objects.requireNonNull(topping)); // 這里不能return T,所以先自己寫一個self()函數來代替(返回還未構成的類) return self(); } abstract Pizza build(); // Subclasses must override this method to return "this" protected abstract T self(); } // <?>:只要是繼承了Builder的參數都可用 Pizza(Builder<?> builder) { toppings = builder.toppings.clone(); // See Item 50 } }// 再來兩個子類披薩 // 重寫之前的抽象函數,并且構造函數中要有super(builder) public class NyPizza extends Pizza { public enum Size { SMALL, MEDIUM, LARGE } private final Size size; public static class Builder extends Pizza.Builder<Builder> { private final Size size; public Builder(Size size) { this.size = Objects.requireNonNull(size); } @Override public NyPizza build() { return new NyPizza(this); } @Override protected Builder self() { return this; } } private NyPizza(Builder builder) { super(builder); size = builder.size; } } public class Calzone extends Pizza { private final boolean sauceInside; public static class Builder extends Pizza.Builder<Builder> { private boolean sauceInside = false; // Default public Builder sauceInside() { sauceInside = true; return this; } @Override public Calzone build() { return new Calzone(this); } @Override protected Builder self() { return this; } } private Calzone(Builder builder) { super(builder); sauceInside = builder.sauceInside; } }// 然后實際使用的時候 // 使用類名建builder,一直builder下去,最后讓builder來build對象出來。 NyPizza pizza = new NyPizza.Builder(SMALL) .addTopping(SAUSAGE).addTopping(ONION).build(); Calzone calzone = new Calzone.Builder() .addTopping(HAM).sauceInside().build();

三. 用私有構造器或枚舉類型強化Singleton屬性

  • 單例模式

方法一:公有靜態成員是個final域

// Singleton with public final field public class Elvis { // 公有 靜態 final public static final Elvis INSTANCE = new Elvis(); // 構造函數私有化 private Elvis() { ... } public void leaveTheBuilding() { ... } }

方法二:公有的成員是個靜態工廠

相對于方法一,畢竟類的成員還是要用方法來訪問比較好。

// Singleton with public final field public class Elvis { // 把public 變成 private private static final Elvis INSTANCE = new Elvis(); // 構造函數私有化 private Elvis() { ... } // 公有靜態方法,返回唯一的實例。 public static Elvis getInstance(){return INSTANCE} public void leaveTheBuilding() { ... } }

方法三:一個包含單個元素的枚舉類型

  • Java的enum和C++的差別很大。
  • 這樣子寫會比較簡便。
// Enum singleton - the preferred approach public enum Elvis{// 只有一個“實例”INSTANCE;public void leaveTheBuilding(){...} }

四. 通過私有構造器強化不可實例化的能力

  • 這塊感覺沒啥好講的,就是給構造函數加個private。
  • 好壞處之類的可以參考書里的內容。

總結

以上是生活随笔為你收集整理的【Effective Java】第二章:静态工厂、构建器、强化Singleton属性、私有构造器、的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。