考虑使用静态工厂方法替代构造方法
轉自 https://www.cnblogs.com/chenpi/p/5981084.html
閱讀目錄
- 創建對象
- 注意區分靜態工廠方法和工廠方法模式
- 使用靜態工廠方法的優勢
- 使用靜態工廠方法的缺點
創建對象
構造方法創建對象
在Java中,創建對象常用的方法是通過公有構造方法創建;
舉個例子:如下,是Boolean類的一個構造方法,以及通過該構造方法創建一個Boolean對象;
public Boolean(String s) {this(toBoolean(s));} Boolean bTrue = new Boolean("true");靜態工廠方法創建對象
其實,創建對象還有另外一種方法,通過公有靜態工廠方法來創建對象,不過這種方法往往容易被程序員忽略;
舉個例子,如下是Boolean類的valueOf方法,以及通過該靜態工廠方法返回的Boolean實例,注意,這里并沒有創建Boolean實例對象,而是返回事先創建好的Boolean對象;
public static Boolean valueOf(String s) {return toBoolean(s) ? TRUE : FALSE;} Boolean bTrue = Boolean.valueOf("true");注意區分靜態工廠方法和工廠方法模式
注意,這里的靜態工廠方法與設計模式里的工廠方法模式不是一個概念:
- 靜態工廠方法通常指的是某個類里的靜態方法,通過調用該靜態方法可以得到屬于該類的一個實例;
- 工廠方法模式是一種設計模式,指的是讓具體的工廠對象負責生產具體的產品對象,這里涉及多種工廠(類),多種對象(類),如內存工廠生產內存對象,CPU工廠生產CPU對象;
不過,如果要說相似的話,靜態工廠方法跟簡單工廠模式倒有那么點像,不過區別也挺大,簡單工廠模式里的靜態工廠方法會創建各種不同的對象(不同類的實例),而靜態工廠方法一般只創建屬于該類的一個實例(包括子類);
使用靜態工廠方法的優勢
1、可讀性更強
?假設我們需要寫一個產生隨即數的類RandomIntGenerator,該類有兩個成員屬性:最小值min和最大值max,
假設我們的需求是需要創建三種類型的RandomIntGenerator對象,
1、大于min,小于max;
2、大于min 小于Integer.MAX_VALUE;
3、大于Integer.MIN_VALUE 小于max
如果我們不使用靜態工廠方法,代碼一般如下設計:
class RandomIntGenerator {/*** 最小值*/private int min = Integer.MIN_VALUE; /** * 最大值 */ private int max = Integer.MAX_VALUE; /** * 大于min 小于max * @param min * @param max */ public RandomIntGenerator(int min, int max) { this.min = min; this.max = max; } /** * 大于min 小于Integer.MAX_VALUE */ public RandomIntGenerator(int min) { this.min = min; } // 報錯:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator // /** // * 大于Integer.MIN_VALUE 小于max // */ // public RandomIntGenerator(int max) // { // this.max = max; // } }觀察以上代碼,我們發現,以上代碼不僅可讀性差(new RandomIntGenerator(1, 10)與new RandomIntGenerator(10),不查文檔,不看注釋很難知道其創建的對象的具體含義),而且在設計最后一個構造方法的時候,還報錯,因為已經存在一個參數一致的工作方法了,提示重復定義;
那么假設我們使用靜態工廠方法會怎樣呢,如下所示:
class RandomIntGenerator {/*** 最小值*/private int min = Integer.MIN_VALUE; /** * 最大值 */ private int max = Integer.MAX_VALUE; /** * 大于min 小于max * @param min * @param max */ public RandomIntGenerator(int min, int max) { this.min = min; this.max = max; } /** * 大于min 小于max * @param min * @param max */ public static RandomIntGenerator between(int min, int max) { return new RandomIntGenerator(min, max); } /** * 大于min 小于Integer.MAX_VALUE */ public static RandomIntGenerator biggerThan(int min) { return new RandomIntGenerator(min, Integer.MAX_VALUE); } /** * 大于Integer.MIN_VALUE 小于max */ public static RandomIntGenerator smallerThan(int max) { return new RandomIntGenerator(Integer.MIN_VALUE, max); } }成功滿足需求:創建三種類型的RandomIntGenerator對象,而且創建對象的時候,代碼可讀性比使用構造方法強;
2、調用的時候,不需要每次都創建一個新對象
JDK中的Boolean類的valueOf方法可以很好的印證這個優勢,在Boolean類中,有兩個事先創建好的Boolean對象(True,False)
public final class Boolean implements java.io.Serializable,Comparable<Boolean> { /** * The {@code Boolean} object corresponding to the primitive * value {@code true}. */ public static final Boolean TRUE = new Boolean(true); /** * The {@code Boolean} object corresponding to the primitive * value {@code false}. */ public static final Boolean FALSE = new Boolean(false);當我們調用Boolean.valueOf("true")方法時,返回的就是這兩個實例的引用,這樣可以避免創建不必要的對象,如果使用構造器的話,就達不到這種效果了;
public static Boolean valueOf(String s) {return toBoolean(s) ? TRUE : FALSE;}?3、可以返回原返回類型的任何子類型對象
//RedDog和BlackDog為Dog的子類public static Dog getInstance(){return new RedDog();//或者return new BlackDog(); }4、代碼更加簡潔
package tmp;class MyMap<K,V> {/** * */ public MyMap() { } public static <K,V> MyMap<K,V> newInstance(){ return new MyMap<K, V>(); } } public class Main { public static void main(String[] args) { MyMap<String, String> map1 = new MyMap<String, String>(); //更加簡潔,不需要重復指明類型參數,可以自行推導出來 MyMap<String, String> map2 = MyMap.newInstance(); } }使用靜態工廠方法的缺點
?1、如果類不含public或protect的構造方法,將不能被繼承;
如下類,不能被其它類繼承;
class MyMap<K,V> {/****/private MyMap() { } public static <K,V> MyMap<K,V> newInstance(){ return new MyMap<K, V>(); } }2、與其它普通靜態方法沒有區別,沒有明確的標識一個靜態方法用于實例化類
?所以,一般一個靜態工廠方法需要有詳細的注釋,遵守標準的命名,如使用getInstance、valueOf、newInstance等方法名;
?
?參考自effective java第一條
轉載于:https://www.cnblogs.com/lijingran/p/8543680.html
總結
以上是生活随笔為你收集整理的考虑使用静态工厂方法替代构造方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: J2EE下的常用设计模式
- 下一篇: maven打包到本地库