Effective Java讀書筆記(五)

用enum代替int常量

// Enum type with data and behavior
public enum Planet {
    MERCURY (3.302e+23, 2.439e6),
    VENUS   (4.869e+24, 6.052e6),
    MARS    (5.975e+24, 6.37e86),

    ...

    NEPTUNE (1.024e=26, 2.477e7);

    private final double mass;              // in kilograms
    private final double radius;            // in meters
    private final double serfaceGravity;    // in m / s^2

    // Universal gravitational constant in m^3 /kg s^2
    private static final double G = 6.67300e-11;

    // Constructor
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        surfaceGravity = G * mass / (radius * radius);
    }

    public double mass()            { return mass; }
    public double radius()          { return radius; }
    public double surfaceGravity()  { return surfaceGravity; }

    public double surfaceWeight(double mass) {
        return mass * surfaceGravity; // F = ma;
    }
}

將不同的行爲與每個常量關聯。

// Enum type with constant-specific method implementations
public enum Operation {
    PLUS    { double apply(double x, double y){ return x + y; } },
    MINUS   { double apply(double x, double y){ return x - y; } },
    TIMES   { double apply(double x, double y){ return x * y; } },
    DIVIDE  { double apply(double x, double y){ return x / y; } };

    abstract double apply(double x, double y);
}

策略枚舉。

// The strategy enum pattern
enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY),
    WEDNESDAY(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 payType.pay(hoursWorked, payRate);
    }

    // The strategy enum type
    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 hrs, double payRate);

        double pay(double hoursWorked, double payRate) {
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked, payRate);
        }
    }
}

用實例域代替序數

不要根據枚舉的序數導出與它關聯的值,而是要將它保存在一個實例域中。

“大多數程序員都不需要這個方法(oridinal)。它是設計成用於像E怒罵Set和E怒罵Map這種基於枚舉的通用數據結構的。”

用EnumSet代替位域

// Bit field enumeration constants
public class Text {
    public static final int STYLE_BOLD          = 1 << 0;
    public static final int STYLE_ITALIC        = 1 << 1;
    public static final int STYLE_UNDERLINE     = 1 << 2;
    public static final int STYLE_STRIKETHROUGH = 1 << 3;

    // Parameter is bitwise OR of zero or mote STYLE
    public void applyStyles(int stype) { ... }
}

text.applyStyles(STYLE_BOLD | STYPE_ITALIC);

// EnumSet a modern replacement for bit fields
public class Text {
    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }

    // Any set could be passed in, but EnumSet is clearly best
    public void applyStyles(Set<Style> styles) { ... }
}

text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

用EnumMap代替序數索引

下面的類用來表示一種烹飪用的香草:

public class Herb {
    public enum Type { ANNUAL, PERENNIAL, BIENNIAL }

    private final String name;
    private final Type type;

    Herb(String name, Type type) {
        this.name = name;
        this.type = type;
    }

    @Override public String toString(){
        return name;
    }
}

現在假設有一個香草的數組,表示一座花園中的職務, 要按照類型(一年生、多年生或者兩年生植物)進行組織之後將這些植物列出來。

// Using oridinal() to index an array - DON'T DO THIS!
Herb[] garden = ...;

Set<Herb>[] herbsByType = (Set<Herb[]>)new Set[Herb.Type.values().length];
for(int i = 0; i < herbsByType.length; i++)
    herbsByType[i] = new HashSet<Herb>();

for(Herb h : garden) 
    herbsByType[h.types.oridinal()].add(h);

// Print the result
for(int i = 0; i < herbsByType.length; i++){
    System.out.printf( ... );
}

// Using and EnumMap to associate data with an enum
Map<Herb.Type, Set<Herb>> herbsByType = 
    new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);

for(Herb.Type t : Herb.Type.values())
    herbsByType.put(t, new HashSet<Herb>());

for(Herb h : garden){
    herbsByType.get(h.type).add(h);

System.out.println(herbsByType);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章