一. 使用靜態工廠方法代替構造器
1. 一個類對外提供獲取自身實例對象的方法:
- 提供公有構造器;
- 公有的靜態工廠方法(一個返回當前類實例的靜態方法,包括當不限於我們平時所寫的單例);
2. 靜態工廠方法的優勢 :
a. 可以隨意組合要初始化的屬性,通過不同的命名,不僅可以避免構造器的限制(一個類只能有一個帶有指定籤名的構造器),而且可以做到顧名思義;
b. 可以不用在每次調用時都創建一個新的對象,可以使用預先構建好的對象,或將構建好的對象緩存起來,進行重複利用,適用於經常請求創建相同對象,並且創建對象的代價很高,如常見的單例模式寫法就是對這一點的應用;實例受控的類:能為重複的調用返回相同的類,有助於類控制某個時刻哪些實例應該存在,功能如下:
1.確保它是一個Singleton或者是不可實例化的;
2.使得不可變的類不會存在兩個相等的實例,即當切僅當a==b時,才有a.equals(b)=true,如果保證了這一點, 就可以使用==代替equals,這樣可以提高性能,枚舉類型保證了這一點 ;
(==為hash地址相同,即同一個對象;equals為實例內容相同)
c. 可以返回原返回值類型的任何子類型的對象,有更好的靈活性,而且可以隱藏實現類(子類),使API更簡潔,適用於基於接口的框架;
(如可以用工廠方法的不同命名標識不同的子類對象,也可以同一個工廠方法,通過參數(如Type)進行判斷,返回不同類型的子類對象)
d. 創建參數化類型實例(即泛型)時,使代碼更簡潔,如:
3. 靜態工廠方法的缺點
a. 類如果不含公有的(public)或受保護的(protected)構造器,就不能被子類化,不方便擴展和形成關係體系;
(不過某些情況也可以用組合代替繼承,同樣可以實現代碼的復用)
(組合:即該類的實例做為新類的一個屬性)
b. 與其他靜態方法沒有任何區別,不方便使用者查找使用;
(可以通過添加注釋以及命名規範,彌補這個問題)
4. 實例演示:構造器與靜態工廠方法
5. 之前有自學過iOS開發,靜態工廠獲取實例的方式,在Object-c中深有體現,只是他們叫做類工廠方法,就像下面代碼這樣:
二. 遇到多個構造器參數時要考慮使用構建器(建造者模式)
如果有大量的可選參數需要任意組合,我們來想想看有哪些實現方案呢?
1. 使用構造器:不能任意的組合;
2. 使用公有靜態工廠方法:需要提前寫出足夠多組合的工廠方法,而且參數過多時通過命名區分也將很不方便;
3. 使用JavaBeans:即無參構造+setter方法,但是這使得構造過程分到了多個調用中,而且不能有效的保證一致性,還有就是阻止了把類做成不可變的可能,需要額外保證它的線程安全性;
4. 使用Builder模式:
優點:既保證了安全性,又有很好的可讀性,而且方便對參數添加約束條件,也可以自動填充某些參數而不提供給調用者去修改(即對客戶端隱藏一些屬性);
缺點:代碼量增多,可能增加內存開銷;
適用於參數比較多的情況,以上面所用對Person類為例;
通過建造者創建實例:
三. 用私有構造器或者枚舉類型強化Singleton屬性
- 實例受控;
- 單例模式的餓漢式,懶漢式,都是需要將構造器私有化;
- 單元素的枚舉類型已經成為實現 Singleton 的最佳方法;
四. 通過私有構造器強化不可實例化的能力
有些類只有靜態方法和靜態屬性,如一些工具類,比如自定義日誌工具類LogUtil,我們不希望它可以創建實例,然而一個類在缺少構造器時,系統會默認提供一個公有無參的構造方法,這時我們可以顯示的提供一個私有的構造方法,以保證該類不可實例化;
五. 避免創建不必要的對象
例1:將字符串轉為boolean類型的實現方法,使用Boolean.valueOf("true")要優於new Boolean("true"),其源碼內部實現如下:
例2:還是以上面的Person類為例,現在新增加一個判斷是否生育高峰期出生的方法;
注意這裡是說避免創建不必要的對象,而不是儘量少的創建對象;
六. 消除過期的對象引用
一般而言,只要類是自己管理內存,就應當注意內存洩漏問題;
例如:棧實現類ArrayStack,當棧先增長後收縮,棧內還維護著過期引用,這種情況稱為無意識的對象保持,那麼就需要在pop()方法中將已經出棧的元素設為空;
內存洩漏另一個常見來源是緩存,有下面幾種解決方案:
1. 使用WeakHashMap代表緩存,緩存中的項過期後就會自動被刪除;
2. 使用後臺線程定時的清除沒用的緩存,或者添加新的緩存時進行清除,使用LinkedHashMap.removeEldestEntry()就可以實現後一種方案;
3. 對於更加複雜的緩存,必須直接使用 java.lang.ref;
4. 監聽器和其他回調:要取消註冊或使用weak reference,如只將他們保存為WeakHashMap中的鍵;
七. 避免使用終結方法
finalizer通常是不可預測的,也是很危險的,一般是不必要的,除非作為安全網,或者為了終止非關鍵的本地資源,若使用了終結方法,就要記住調用super.finalize,如果需要把終結方法與公有的非final類關聯起來,請考慮使用終結方法守衛者,以確保即使子類的終結方法未能調用super.finalize, 該終結方法也會被執行;
我是今陽,如果想要進階和了解更多的乾貨,歡迎關注公眾號」今陽說「接收我的最新文章