Effective java5——枚举

来源:互联网 发布:手写画板软件 编辑:程序博客网 时间:2024/05/16 07:34

Java的枚举比C++/C#更加强大,它本身就是一个线程安全的单态模式,java的枚举可以添加字段和方法,也可以添加main方法。

(1)枚举对象相同的行为方法:

计算九大行星表面物体重量的枚举代码
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;//星星质量

    private final double radius;//星星半径

    private final double surfaceGravity;//星星表面重力加速度

    private static final double G = 6.67300E-11;//万有引力常量

    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 surfaceWeight(double mass){//计算行星表面给定质量的物体的重力m*g

       return mass * surfaceGravity;

  }

 public static void main(String[] args){

          double earthWeight = 175.0;

          double mass = earthWeight / Planet.EARTH.surfaceGravity();

           for(Planet p : Planet.values()){

                System.out.println("Weight on %s is %f%n",p,p.surfaceWeight(mass));

   }

 }

}

上述代码可以将地球上质量为175kg物体在九大行星上对应的重力打印出来。

由于九大行星枚举的获取质量、半径、表面重力加速度和表面物体重力行为完全相同,因此可以将mass(),radius(),surfaceGravity()和surfaceWeight(double mass)方法作为枚举类的类方法。

(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){

                 retun 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);

    public static void main(String[] args){

        double x = 2.0;

        double y =4.0;

         for(Operation op :Operation.values()){

              System.out.println("%f %s %f = %f%n",x,op,y,op.apply(x,y));

         }

   }

}

枚举中的枚举元素就是枚举类的实例对象,对于枚举实例相同的行为可以提取为枚举类的成员方法如toString(),对于枚举类实例对象不同的行为,需要在枚举类中声明为抽象方法,然后在枚举实例对象中提供具体的实现,例如apply(double x,double y)方法。

(3)枚举策略:

下面是一个计算加班工资的枚举,在正常工作日超过8小时的算加班,周报也算是加班,例子代码如下:

enum PayrollDay{

      MONDAY(PayType.WEEKDAY),

      TUESDAY(PayType.WEEKDAY),

      WEDNSDAY(PayType.WEEKDAY),

      THURSDAY(PayType.WEEKDAY),

       FRIDAY(PayType.WEEKDAY),

       SATURDAY(PayType.WEEKDAY),

       SUNDAY(PayType.WEEKDAY);

       private final PayType payType;

       PayrollDay(PayType payType){

            this.payType = payType;

 }

  double pay(double hoursWorked,double payRate){

        return payType.pay(hoursWorked,payRate);

  }

  //策略枚举

   private enum PayType{

         WEEKDAY{

            double overtimePay(double hoursWorked,double payRate){

                 return hours <= HOURS_PER_SHIFT ? 0: (hours - HOURS_PER_SHIFT) * payRate /2;

            }

    },

    WEEKEND{

             double overtimePay(double hoursWorked,double payRate){

                  return hours * payRate/2;

              }

    };

   private static final int HOURS_PER_SHIFT = 8;

   abstract double overtimePay(double hoursWorked,double payRate);

    double pay(double hoursWorked,double payRate){

            double basePay = hourseWorked * payRate;

            return basePay + overtimePay(hoursWorked,payRate);

     }

  }

}

上述例子中,工作日枚举对象共享相同的行为,而周末枚举对象共享相同的行为,因此将工作日和周末抽取为内部策略枚举,当增加不同行为的枚举实例时,只需要修改内部枚举策略即可,客户端使用代码不用做修改。

(4)枚举扩展:

 枚举无法通过继承来扩展,但是枚举可以通过实现接口来进行扩展,以数学运算为例演示代码如下:

//数学运算接口

public interface Operation{

       double apply(double x,double y);

}

//基本运算

public enum BasicOperation implements Operation{

       PLUS("+"){

         public double apply(double x,double y){

            return x+y;

        }

   },

   MINUS("-"){

         public double apply(double x,double y){

                return x-y;

          }

   },

   TIMES("*"){

          public double apply(double x,double y){

               return x*y;

          }

    },

    DIVIDE("/"){

          public double apply(double x,double y){

                  return x/y;

          }

   };

   private final String symbol;

   BasicOperation(String symbol){

           this.symbol = symbol;

   }

   @Override public String toString(){

          return symbol;

     }

     public static void main(String[] args){

            double x= 2.0;

            double y=4.0;

             for(Operation op : BasicOperation.values()){

               System.out.printf("%f %s %f = %f%n",x,op,y,op.apply(x,y));

             }

     }

}

//扩展运算

public enum ExtendedOperation implements Operation{

         EXP("^"){

             public double apply(double x,double y){

                 return Math.pow(x,y);

             }

      },

      REMAINDER("%"){

             public double apply(double x,double y){

                 return x % y;

            }

     };

     private final String symbol;

     ExtendedOperation(String symbol){

           this.symbol = symbol;

     }

   @Override public String toString(){

          return symbol;

    }

   public static void main(String[] args){

            double x = 2.0;

            double y = 4.0;

            for(Operation op : ExtendedOpreation.values()){

                System.out.printf("%f %s %f = %f%n",x,op,y,op.apply(x,y));

           }

    }

}

虽然无法编写可扩展的枚举类型,却可以通过编写接口以及实现该接口的基础枚举类型来对枚举进行扩展。

 

0 0