Effective Java Item2 建構函式參數過多可考慮使用建造器
整理Effective Java書中Item 2: Consider a builder when faced with many constructor parameters心得筆記
主旨
由於靜態工廠(static factories)和建構函式(constructors)還是有它的限制的,當參數變多了就不太適合,而進而衍伸出了這篇建造者模式(builder pattern)以及相關使用說明。
點出問題
- 典型的可伸縮建構函式(telescoping constructor)
Employee alice = new Employee("Chen", "Alice", "F", 25, null, null, 'Y');
當我們要使用它看起來會像這樣,而這類參數稍多的建構函式(constructor)有下面幾項問題:
無法快速了解,如果不點進去Employee class裡面查看,是不會知道傳進去的參數定義。
有序性,一定要按照建構函式裡定的順序設值。
不太優雅,有時候必須為了滿足參數傳了null。
沒有彈性,後來需求增加多了一個email,就在constructor裡面往後加,然後去找出所有使用到的地方去修改,明明很清楚這樣是硬幹(尤其要加第4個參數的時候…),但也懶得調整了心想先這樣吧,應該很多人都有類似經驗…
- JavaBeans pattern
另一種方式乾脆不要在constructor設值,用set的方式去設置所需要的
當我們要使用它看起來會像這樣
這總方式看起來可讀性好多了,但還是有不足之處:
- 太自由了,例如有個開發者少設置了一個必要欄位,如果又沒有嚴謹的驗證測試,上線可能會導致runtime exception。
- inconsistent state問題,多執行緒的環境下同時操作同一個物件,執行緒B把值改掉了導致執行緒A處理錯誤,也因為多執行緒環境無規律不好重現問題,有時候你需要使它成為不可變物件 (Immutable object)才行。
- 建造者模式(builder pattern)
進入本篇主題建造者模式(builder pattern)這個就是專門來優雅的解決上述問題的方法
Employee alice = new Employee.Builder("Chen", "Alice", "F").setAge(25).setSingle(true);
其中要注意的是Employee建構函式(constructor)是private
的,而將必填欄位放在Builder的constructor裡面。說明只能透過Builder來創建,整體看起來更加優雅、容易閱讀、可擴展、無序性、不可變的、具安全性。
小結
本章節就是在介紹建造者模式(builder pattern),其實很多人已經有使用過,可以參考jdk裡的StringBuilder原始碼,這個是design pattern入門款之一,多嘗試看看使用這種方式。
補充小技巧
有人會問如果必填欄位很多怎麼使用Builder,不是也是要Builder的constructor放很多參數嗎?其實可以使用JDK7裡的
Objects.requireNonNull()
來擋控,至少能讓你在單元測試時期就發現bug。