要說明問題最好的辦法就是結合例子,比如我們要定義一年的12個月,往往會想到枚舉,假設我們要定義一個返回某年某個月的天數的方法,我們知道一個月一般是30,31天,其中2月比較特殊,閏年是28天,其他年份是29天,如果單純用swtich的話顯然不是一種很好的代碼風格,這個例子還好,因爲我們知道一年12月不會變,但有的枚舉可能在今後添加新的類型,這樣我們就不得不去修改原有的switch了,明顯不符合開--閉原則,影響維護並且容易引入Bug。
這時我們可以利用嵌套枚舉和接口結合的方法來實現開閉原則的思想。
public enum Year {
JAN(MonType.BIG), FEB(MonType.SPECIAL), MAR(MonType.BIG), APR(MonType.SMALL), MAY(
MonType.BIG), JUN(MonType.SMALL),//剩餘月份略掉;
Year(MonType type) {
this.type = type;
}
private final MonType type;
public int ContainDays(int year) {
return type.countResult(year);
}
private enum MonType implements Count {
BIG {
public int countResult(int num) {
return 31;
}
},
SMALL {
public int countResult(int num) {
return 30;
}
},
SPECIAL {
public int countResult(int num) {
if ((num % 4 == 0 && num % 100 != 0) || (num % 400 == 0)) {
return 28;
} else {
return 29;
}
}
}
}
}
public interface Count {
public int countResult(int num);
}
在上面這段代碼裏Year枚舉的ContainDays方法返回某年某月的天數,因爲大月,小月,閏年和非閏年的2月返回的天數都是不一樣的,也就是根據輸入參數計算的策略可能不一樣,這種情況下我們應抽象出接口來適應這種變化,但是要是直接在Year枚舉裏12月的類型實例一一實現該接口就會帶來很多重複代碼(代碼有臭味了),因爲像1,3,5等都是返回31天的,也就是計算方法一樣,而如用嵌套枚舉(相當於內部類),外層枚舉把處理方法委託給了內部枚舉,讓內部枚舉(代表每個月計算天數的不同類型)來具體實現Count接口(用來返回每月天數),則很好的消除了冗餘代碼,並且今後要是添加其他處理類型,只需再次實現Count接口,原有的代碼無需改變,很好的實現了開閉原則。