`
hwy1782
  • 浏览: 150482 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java 枚举类型使用

 
阅读更多

这几天在阅读《effective java》一书中enum相关的章节。笔记如下:

 

下面的例子中,提供了四种枚举型常量,这些枚举常量含有可以进行加减乘除操作的方法。

 

public enum Opration_V1 {
	
	PLUS,MINS,TIMES,DIVIES;
	
	double apply(double x,double y){
		switch (this) {
		case PLUS:
			return x+y;
		case MINS:
			return x-y;
		case TIMES:
			return x*y;
		case DIVIES:
			return x/y;
		}
		throw new AssertionError();
	}
	
}

 

 修改上述代码如下:

public enum Opration_V1 {
	
	PLUS,MINS,TIMES,DIVIES,
        ERROR;
	
	double apply(double x,double y){
		switch (this) {
		case PLUS:
			return x+y;
		case MINS:
			return x-y;
		case TIMES:
			return x*y;
		case DIVIES:
			return x/y;
		}
		throw new AssertionError();
	}
	
}

 

写道
上述代码中添加了一个新的枚举常量error,但是没有添加相应的apply()方法,因此在运行时调用Opration_V1.ERROR.apply()会报错。这种错误在编译期间不会出现,只是在运行期出现。

 

为了解决上述问题,可以采用如下的方法:

public enum Opration_V2 {
	
	PLUS{double apply(double x, double y) {return x+y;}},
	MINS{double apply(double x, double y) {return x-y;}},
	TIMES{double apply(double x, double y) {return x*y;}},
	DIVIES{double apply(double x, double y) {return x/y;}};
	
	abstract double apply(double x,double y);
	
}

 枚举类Opration_V2中添加了一个抽象方法apply();对于具体的枚举成员,都需要实现这个抽象方法。因此添加新的枚举成员的时候,编辑器会自动提示用户添加相应的apply方法。在编译期间就解决版本1中的问题。

 

可以对版本2进一步优化。

 

package com.enumDemo;

import java.util.Map;

import com.google.common.collect.Maps;

/**
 * @author E-mail: hwy1782@gmail.com
 * @date  : 2013-1-30 04:16:24
 */
public enum Opration_V3 {
	
	PLUS("+"){double apply(double x, double y) {return x+y;}},
	MINS("-"){double apply(double x, double y) {return x-y;}},
	TIMES("x"){double apply(double x, double y) {return x*y;}},
	DIVIES("/"){double apply(double x, double y) {return x/y;}};
	
	private String symbol;
	
	private Opration_V3(String symbol) {
		this.symbol = symbol;
	}
	
	abstract double apply(double x,double y);
	
	@Override
	//use symbol to display enum
	public String toString() {
		//Returns the name of this enum constant, as contained in the declaration
		return symbol;
	}
	
	/**
	 * get enum of the symbol 
	 * @param symbol
	 * @return
	 */
	public static Opration_V3 formString(String symbol){
		return stringToEnum.get(symbol);
	}
	
	private static final Map<String,Opration_V3> stringToEnum = Maps.newHashMap();
	
	static{
		for(Opration_V3 op : Opration_V3.values()){
			stringToEnum.put(op.toString(), op);
		}
	}
	
	
	
}

 

上述部分主要进行了如下几点优化:

1.将枚举常量与特定的符号关联起来,通过重写enum的toSting()方法,对外展示枚举常量的symbol

2.添加一个fromString()方法,返回symbol对应的枚举常量。

 

上面的例子还存在一些问题。版本3中每一个enum类型对应一个apply()方法,但是如果存在一种情况:几个enum常量对应相同的apply()方法,是不是每个enum常量都把相应的apply()方法再拷贝一遍呢?下面有一种解决方案:采用switch的方式,匹配对应的方法:

package com.enumDemo;
/**
 * @author E-mail: hwy1782@gmail.com
 * @date  : 2013-1-31 上午11:32:51
 * Payroll 枚举工资单,计算每天的工资
 * 
 * </br>缺点:
 * </br>
 * 添加一个新的enmu,忘记在pay()方法中添加相应的switch条件的话,就会采用default的计算pay的方法。
 * 
 */
public enum PayrollDay_v1 {

	MONDAY,TUESDAY,WEDNESDAY,THRSDAY,FRIDAY,SAYURDAY,SUNDAY;
	
	private static final int DEFAUL_WORK_HOUR = 8;
	
	double pay(double workHoues,double payRate){
		double basicPay = DEFAUL_WORK_HOUR * payRate;
		double overTimePay = 0;
		switch (this) {
		case SAYURDAY: case SUNDAY:
			overTimePay = workHoues * payRate * 2;
		default:
			overTimePay = (workHoues - DEFAUL_WORK_HOUR) * payRate * 2;
		}
		
		return basicPay + overTimePay;
	}
	
}

 

 但是上述方案同样存在一些问题,新增一个enm常量,但是忘记添加相应的switch条件,则这个新增的enum会执行默认的方法,存在很大的隐患。

 

下面提供了一种解决方案,枚举策略方法:

package com.enumDemo;
/**
 * @author E-mail: hwy1782@gmail.com
 * @date  : 2013-1-31 上午11:32:51
 * Payroll 枚举工资单,计算每天的工资
 * 
 * </br>改进点:
 * </br>
 * 修复版本1中存在的缺陷:
 * 新增一个枚举的时候忘记添加相应的计算工资的方法。</br>
 * 方法:
 * 1.添加一个abstract 方法,每个枚举常量必须实现这个abstract方法,在这个abstract方法中实现每个enum常量的pay()方法。
 * 但是上述的方法有一个缺陷,每个枚举常量必须都实现这个abstract方法,不能做到这个方法的复用。
 * 
 * 2.此处使用策略枚举(strategy enum)来解决这个问题
 * 枚举策略的使用条件是:
 * <br/>
 * 枚举常量中: 存在多个常量共用一个方法的时候,抽象公用方法为枚举
 * <br/>
 * 可以将这种策略枚举添加在外部枚举常量的构造函数中,解决新加常量时遗忘添加方法的问题
 * 
 */
public enum PayrollDay_v2 {

	MONDAY(PayType.WEEKDAY),
	TUESDAY(PayType.WEEKDAY),
	WEDNESDAY(PayType.WEEKDAY),
	THRSDAY(PayType.WEEKDAY),
	FRIDAY(PayType.WEEKDAY),
	SAYURDAY(PayType.WEEKDAY),
	SUNDAY(PayType.WEEKEND);
	
	private final PayType payType;
	
	PayrollDay_v2(PayType type){
		this.payType = type;
	}
	
	
	public double pay(double workHourse,double payRate){
		return payType.pay(workHourse, payRate);
	}
	
	//策略枚举
	private enum PayType{
		WEEKDAY{
			@Override
			double overtimePay(double workHourse,double payRate) {
				return workHourse > DEFAUL_WORK_HOUR ? 0 : (workHourse - DEFAUL_WORK_HOUR)*payRate;
			}
		},
		WEEKEND{
			@Override
			double overtimePay(double workHourse,double payRate) {
				return workHourse * payRate;
			}
		};
		
		static final int DEFAUL_WORK_HOUR = 8;
		
		abstract double overtimePay(double workHourse,double payRate);
		
		double pay(double workHourse,double payRate){
			double basicPay = workHourse * payRate;
			return basicPay + overtimePay(workHourse, payRate);
		}
		
	}
	
}

 

测试类如下:

package com.enumDemo;

import org.junit.Test;

/**
 * 
 * @author hongye.hwy
 * 
 */
public class PayrollDay_v2_Drive {

	private static final double DEFAULT_PAY_RATE = 9.8;
	
	@Test
	public void test_PayrollDay() {

		double workHourse = 8;
		
		System.out.printf("%s work %f hours will get %f$",
				PayrollDay_v2.SAYURDAY,workHourse,PayrollDay_v2.SAYURDAY.pay(8, DEFAULT_PAY_RATE));
	}

}

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics