enum 進階應用
Table of contents
用多型取代if-else
public enum VoltageRange {
V100_120, V200_240, V100_240;
public boolean isVoltageInRange(int voltage) {
if (StringUtils.equals("V100_120", name())) {
IntRange v100to120 = new IntRange(100, 120);
return v100to120.containsInteger(voltage);
} else if (StringUtils.equals("V200_240", name())) {
IntRange v200to240 = new IntRange(200, 240);
return v200to240.containsInteger(voltage);
} else if (StringUtils.equals("V100_240", name())) {
IntRange v100to120 = new IntRange(100, 120);
IntRange v200to240 = new IntRange(200, 240);
return v100to120.containsInteger(voltage) || v200to240.containsInteger(voltage);
}
return false;
}
}
package com.bellwin.idcview.device.model;
import org.apache.commons.lang.math.IntRange;
public enum VoltageRange {
V100_120 {
@Override
public boolean isVoltageInRange(int voltage) {
IntRange v100to120 = new IntRange(100, 120);
return v100to120.containsInteger(voltage);
}
},
V200_240 {
@Override
public boolean isVoltageInRange(int voltage) {
IntRange v200to240 = new IntRange(200, 240);
return v200to240.containsInteger(voltage);
}
},
V100_240 {
@Override
public boolean isVoltageInRange(int voltage) {
IntRange v100to120 = new IntRange(100, 120);
IntRange v200to240 = new IntRange(200, 240);
return v100to120.containsInteger(voltage) || v200to240.containsInteger(voltage);
}
};
// 因為 V100_120, V200_240, V100_240 實際上是VoltageRange的instnace,所以必須要宣告一個method(是不是需要為abstract method視需求而定)
public abstract boolean isVoltageInRange(int voltage);
}
改變ordinal的預設行為
JPA如果選擇以@Enumerated(EnumType.ORDINAL)
,他的值一定是一個順序值, 0,
1, 2, 3, 4, …
,沒辦法跳號,而且存入資料庫的值也會是這樣的順序號,無法跳號,
但有時如果我們的物件模型不見得是順序號的時侯,這時就會比較麻煩。
比如說,以家用電源來說,有單相(SINGLE_PHASE)跟三相(THREE_PHASE),但沒有雙相電,雖然我們宣告一個電力相的物件模型為這樣的列舉值
public enum PhaseType {
SINGLE_PHASE(1), THREE_PHASE(3);
}
但JPA若選擇以@Enumerated(EnumType.ORDINAL)
方式存入資料庫,那麼存入db的值是會取決於ordinal()這個method,所以會是單相電會存入’0’,三相電會存入’1’到db。我們可以選擇用@Enumerated(EnumType.STRING)
來處理,但這樣存入db的型態會是字串,另一種較好的方式,改寫列舉型別PhaseType,並要求使用他的對象類別(此例中的AirCon)配合修改
public enum PhaseType {
SINGLE_PHASE(1), THREE_PHASE(3);
// 用parse來決定value真正的值
public static PhaseType parse(int id) {
PhaseType type = null; // Default
for (PhaseType item : PhaseType.values()) {
if (item.getValue() == id) {
type = item;
break;
}
}
return type;
}
private final int value;
PhaseType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
光是這樣是不夠的,使用列舉型別PhaseType的對象,也需要配合修改
- 將原本定義為@Enumerated改成數值型態
- getter跟setter要呼叫PhaseType裡的getValue()跟parse()將PhaseType轉成數值型態
這樣修改後,對於使用AirCon(冷氣機)物件來說,還是使用列舉型別PhaseType,但存入db的由原來的0(單相)、1(三相)變成更直覺的1(單相)、3(三相)
@Entity
public AirCon {
/**
* 原本是宣告成PhaseType列舉型別
*/
//@Enumerated(EnumType.ORDINAL)
//private PhaseType voltageRange;
// 改成宣告為數值
private Integer phaseType;
// getter跟setter要配合修改,將PhaseType轉成int,這樣對使用AirCon來說,還是使用比較直覺的列舉型別PhaseType
@Override
public PhaseType getPhaseType() {
return PhaseType.parse(phaseType);
}
public void setPhaseType(PhaseType phaseType) {
this.phaseType = phaseType.getValue();
}
}