代码改变世界

Item 30 用enum代替int常量类型枚举,string常量类型枚举

2015-04-26 22:58  ttylinux  阅读(507)  评论(0编辑  收藏  举报
1.用枚举类型替代int枚举类型和string枚举类型
public class Show {
  // Int枚举类型
  // public static final int APPLE_FUJI = 0;
  // public static final int APPLE_PIPPIN = 1;
  // public static final int APPLE_GRANNY_SMITH = 2;
 
  public enum Apple {
    FUJI, PIPPIN, GRANNY_SMITH
  }
 
  public enum Orange {
    FUJI, PIPPIN, GRANNY_SMITH
  }
 
2.一个枚举类型可以和行为相关联,枚举类型可包含行为
比如下述,Planet它包含了行为:mass(),radius(),surfaceGravity(),
surfaceWeight( double mass)。当常量具有对应的行为的时候,就可以通过下述方式来实现,在枚举类型中定义行为。
 
public enum Planet {
  MERCURY(3.302e+23, 2.439e6),
  VENUS(4.869e+24, 6.052e6),
  EARTH(5.975e+24, 6.378e6),
  MARS(6.419e+23, 3.393e6),
  JUPITER(1.899e+27, 7.149e7),
  SATURN(5.685e+26, 6.027e7),
  URANUS(8.683e+25, 2.556e7),
  NEPTUNE(1.024e+26, 2.477e7);
 
 
  private final double mass ; // In kilograms
  private final double radius ; // In meters
  private final double surfaceGravity ; // 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
  }
}
 
使用:
public class WeightTable {
        public static void main(String[] args) {
               double earthWeight = Double.parseDouble(args[0]);
               double mass = earthWeight / Planet.EARTH.surfaceGravity();
               for (Planet p : Planet.values())
                     System. out.printf("Weight on %s is %f%n" , p, p.surfaceWeight(mass));
       }
}
Planet枚举类型,有9个枚举常量。每个枚举常量,通过构造器实例化。每个枚举常量有相同的行为。
3.枚举和行为关联,定义特定于某个枚举常量的行为
如下,下述有4个枚举常量。每个枚举常量有特定的行为,每个枚举常量对apply行为有自己的实现,而不是像上述2中的,所有枚举常量共用相同的实现。
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;
              }
       };
 
 
       private final String symbol ;
       Operation(String symbol) {
               this.symbol = symbol;
       }
 
        @Override
        public String toString() {
               return symbol ;
       }
 
        abstract double apply(double x, double y);
 
        // Implementing a fromString method on an enum type - Page 154
        private static final Map<String, Operation> stringToEnum = new HashMap<String, Operation>();
        static { // Initialize map from constant name to enum constant
               for (Operation op : values())
                      stringToEnum.put(op.toString(), op);
       }
 
        // Returns Operation for string, or null if string is invalid
        public static Operation fromString(String symbol) {
               return stringToEnum .get(symbol);
       }
 
        // Test program to perform all operations on given operands
        public static void main(String[] args) {
               double x = Double.parseDouble(args[0]);
               double y = Double.parseDouble(args[1]);
               for (Operation op : Operation.values())
                     System. out.printf("%f %s %f = %f%n" , x, op, y, op.apply(x, y));
 
             Operation plus = Operation. PLUS;  
             System. out .printf("12 %s 13 = %f%n" "plus" , plus.apply(12, 13));
       }
}
 
分析:枚举常量,PLUS,MINUS,TIMES,DIVIDE,这三个是枚举类型Operation的final实例。为了将某个具体的final实例跟特定的方法关联起来,可以这样做:首先,在Operation类中,声明抽象方法apply;然后,每个具体的final实例,实现自己的apply方法。这样,就实现了,具体的枚举常量跟一个具体的方法关联。
4.用枚举类型实现策略模式
策略模式,就是,客户端指定了一个策略,然后,代码就按照该策略执行。客户端可以切换策略,从而让代码按照不同的逻辑执行。
 
public 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);
    }
  }
}
当指定不同的枚举常量的时候,会执行不同的加班策略。每个具体的枚举常量,它对应的加班策略,在声明的时候就确定了。
比如,枚举常量MONDAY,当访问pay方法时,它执行的是PayType枚举类型中的加班计算策略。