記錄讀書心得, 內容不一定和書上一致, 有些是我自己的看法。
參照官網介紹的例子 enum Planet, 可以清楚地明白使用 enum 的好處。書上列舉的好處有:
- 安全、易讀、執行速度不輸 int 的實作版
- 天生 immutable
- 已實作 equals()、hashCode()、Serializable、Comparable
Making the Most of Java 5.0: Enum Tricks 這篇進一步說明使用 enum 的技巧:
- reverse lookup。key 可以是 code 或字串。enum 會自動生成 valueOf(String) 提供字串的反查, 但有覆寫 toString() 的話, valueOf() 就失效了。這時記得提供自己寫的 fromtString() (不能覆寫 valueOf(), 因為 enum 的方法都是 final)
- template method。書上稱這個為「constant-specific method implementations」, 重點是藉由 abstract method 保證之後新增的欄位不會漏實作必要的 method。
這則後半都在討論如何寫出好程式, 讓後續維護的人很難犯錯, 這也是作者不斷強調的精神, 一連串的討論值得細細思考。
當 enum 的行為只差在數值不同時, 一個 method 只有一種行為, 用一個 method 即可; 但若要提供多種不同行為時, 實作上有許多選擇:
- 只用一個 method 使用 switch 來決定行為
- 用 abstract method + constant-specific method implementations 各別實作對應的行為
- 類似上面的作法, 但將運算轉包給 nested enum, 使用 composition 的技巧 (見後文說明)。作者稱這個為「the strategy enum pattern」
第一個作法最簡單, 缺點是增加新的常數時, 不小心漏寫對應的程式時, 不會 compile error, 也不會有 runtime error。第二個作法透過 abstract method, 漏寫會導致 compilation error。
但第二個作法也有個小問題: 不同方法之間無法重用類似的程式, 而重覆的程式容易造成 bug。於是有第三個作法來避免這個問題, 不過也提昇實作複雜度, 程式變得沒那麼易懂。
書上舉的範例是: 定義 enum PayrollDay 來表示星期幾, 並提供方法依當天的工作時數來計算薪資。書上的範例 code 如下:
enum PayrollDay { MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNSDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND); private final PayType payType; PayrollDay(PayType payType) { this.payType = payType; } double pay(double hoursWorked, double payRate) { return this.payType.pay(hoursWorked, payRate); } private enum PayType { WEEKDAY { double overtimePay(double hours, double payRate) { return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT) * payRate / 2; } }, WEEKEND { double overtimePay(double hours, double payRate) { return hours * payRate / 2; } }; private static final int HOURS_PER_SHIFT = 8; abstract double overtimePay(double hours, double payRate); double pay(double hoursWorked, double payRate) { double basePay = hoursWorked * payRate; return basePay + overtimePay(hoursWorked, payRate); } } }
這個寫法有兩個特色:
- 將實際的計算外包給 PayType, 藉此共用算法
- 透過 constructor 強迫選擇 PayType。若有新的情況, 比方新年假期要算兩倍薪資, 開發者會記得寫新的 PayType。
依作者的思維, 讓維護的人不易犯錯比較重要。在這前提下, 讓程式沒那麼直接, 是可以容忍的 trade-off。我個人也認為如此, 開發者的功力會持續進步, 就愈來愈能看懂這類「進階技巧」, 而不會覺得這類寫法比較難懂。長遠來看, 是比較好的選擇。
沒有留言:
張貼留言