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的對象,也需要配合修改

  1. 將原本定義為@Enumerated改成數值型態
  2. 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();
    }
}