JAVA枚举类状态机 与 Java枚举策略模式

写的比较晚了,贴代码供参考


1、普通的enum方法设计如下,缺点是不方便维护,因为是switch语句,容易在扩展的时候忘了改相关的代码。但如果你的代码千年不变,这个缺点就不明显。

注意:测试结果参见第2点。

package enumclass;

public enum PayrollBySwitch {
	Monday,
	Tuesday,
	Wendsday,
	Thursday,
	Friday,
	Saturday,
	Sunday;

	private static final int FIXED_WORK_HOUR_PER_DAY = 8;
	
	//加班工资会是基本工资的一半。
	private static final double OVER_TIME_PAY_RATE = 1/2;  
	
	public double pay(double workHours, double payPerHour){
		
		double basePay = workHours  * payPerHour;
		
		double overTimePay = 0;
		switch(this){
		//周六日每个小时都算加班工资
		case Saturday: case Sunday:
			overTimePay = workHours * payPerHour * OVER_TIME_PAY_RATE;
			break;
		default:
			overTimePay = workHours <= FIXED_WORK_HOUR_PER_DAY ? 
					      0 : workHours - FIXED_WORK_HOUR_PER_DAY;
			break;
			
		}
		return basePay+overTimePay;
	}
}

2、enum方法的改进版,使用了enum strategy模式。要点:

1、设计一个private的enum,作为strategy的抽象。

2、顶层enum的构造器需要传入策略PayType。

3、策略类需要定义一个抽象类,让private enum去实现这个方法。这里用到enum的另一个特性:特定于常量的方法(Constant-specific class body的Constant -specific method implementation)。

package enumclass;

public enum PayrollByEnumStrategy {
	Monday(PayType.WeekDay),
	Tuesday(PayType.WeekDay),
	Wendsday(PayType.WeekDay),
	Thursday(PayType.WeekDay),
	Friday(PayType.WeekDay),
	Saturday(PayType.WeekEnd),
	Sunday(PayType.WeekEnd);

	PayType payType;
	private PayrollByEnumStrategy(PayType payType) {
		this.payType = payType;
	}
	
	public double pay(double workHours, double payPerHour){
		return payType.pay(workHours, payPerHour);
	}
	
	
	
	private enum PayType{
		
		WeekDay{

			@Override
			double overTimePay(double workHours, double payPerHour) {
				double overTimePay = workHours <= FIXED_WORK_HOUR_PER_DAY ? 
					      0 : (workHours - FIXED_WORK_HOUR_PER_DAY)*payPerHour*OVER_TIME_PAY_RATE;
				return overTimePay;
			}
			
		},
		WeekEnd{

			@Override
			double overTimePay(double workHours, double payPerHour) {
				double overTimePay = workHours * payPerHour * OVER_TIME_PAY_RATE;
				return overTimePay;
			}
			
		};
		private static final int FIXED_WORK_HOUR_PER_DAY = 8;
		
		//加班工资会是基本工资的一半。
		private static final double OVER_TIME_PAY_RATE = 1/2;
		
		
		abstract double overTimePay(double workHours, double payPerHour);
		
		public double pay(double workHours, double payPerHour){
			
			double basePay = workHours  * payPerHour;
			
			double overTimePay = overTimePay(workHours,payPerHour);
			return basePay+overTimePay;
		}
		
	}
}

1 和 2的测试结果:

工资总额 by Switch= ¥3510.0
工资总额 by Enum Strategy= ¥3510.0

测试类如下:

package enumclass;

public class WorkPayment {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//计算一周的工资总额——每天工作10小时,每小时400块。
		double sum = 0;
		for(PayrollBySwitch day : PayrollBySwitch.values()){
			sum += day.pay(10, 50);
		}
		
		System.out.println("工资总额 by Switch= ¥"+sum);
		
		
		sum = 0;
		for(PayrollBySwitch day : PayrollBySwitch.values()){
			sum += day.pay(10, 50);
		}
		
		System.out.println("工资总额 by Enum Strategy= ¥"+sum);
	}

}


3、覆盖enum的toString带来的方便。

如下面例子,打印日志时,很方便

package enumclass;

//enum strategy with toString overrided
public enum Operation {
		  PLUS("*")   { double eval(double x, double y) { return x + y; } },
		  MINUS("-")  { double eval(double x, double y) { return x - y; } },
		  TIMES("*")  { double eval(double x, double y) { return x * y; } },
		  DIVIDE ("/"){ double eval(double x, double y) { return x / y; } };

		  String symbol = null;
		  Operation(String symbol){
			  this.symbol = symbol;
		  }
	
		  public String toString(){
			  return symbol;
		  }
		  
		  // Do arithmetic op represented by this constant
		  abstract double eval(double x, double y);
		 
}

测试类
package enumclass;

public class OperationTest {

	 
	  public static void main(String[] args) {
		  double x = 2.000;
		  double y = 4.0000;
		  
		  for(Operation oper : Operation.values()){
			  System.out.printf("%f %s %f = %f%n",x,oper,y,oper.eval(x, y));
		  }
	  }

}

测试结果如下:

2.000000 * 4.000000 = 6.000000
2.000000 - 4.000000 = -2.000000
2.000000 * 4.000000 = 8.000000
2.000000 / 4.000000 = 0.500000


4、最后是状态机的实现,已上传。

要点:

1、enum可以实现interface。

2、状态机维护需要两种对象:Context上下文、States状态

3、Context管理State。

4、用while运行状态机,其实这个while放到Context内更好,应该是状态机自己维护状态,而不是外部通过状态机去控制状态。

5、比较巧的设计是,每个state的操作返回boolean,作为状态是否终止的判断。

资源:http://download.csdn.net/detail/xzongyuan/9871848

State设置为如下时:

context.state(States.WHITE);

运行结果:

Current State = WHITE
Current State = BLUE


package enumstatemachin;

public class InfiniteMachineTest {

	public static void main(String[] args) {
		
		Context context = new ContextImp();
		context.state(States.WHITE);
 	    while(context.state().process(context));
	}
}
package enumstatemachin;

import java.nio.ByteBuffer;


enum States implements State {
    RED {
        public boolean process(Context context) {
            context.state(States.GREEN);
            System.out.println("Current State = " + this);
            return true;
        }
    }, GREEN {
        public boolean process(Context context) {
            context.state(States.BLACK);
            System.out.println("Current State = " + this);
            return true;
        }
    },BLACK {
        public boolean process(Context context) {
            context.state(States.YELLOW);
            System.out.println("Current State = " + this);
            return true;
        }
    },YELLOW {
        public boolean process(Context context) {
            context.state(States.WHITE);
            System.out.println("Current State = " + this);
            return true;
        }
    },WHITE {
        public boolean process(Context context) {
            context.state(States.BLUE);
            System.out.println("Current State = " + this);
            return true;
        }
    },BLUE{
    	public boolean process(Context context) {
    		context.state(States.RED);
            System.out.println("Current State = " + this);
			return false;
    	}  
    };
	
	public abstract boolean process(Context context);
}

package enumstatemachin;

interface State {
    /**
       * @return true to keep processing, false to read more data.
     */
    boolean process(Context context);
}
package enumstatemachin;

import java.nio.ByteBuffer;

public interface Context {
    State state();
    void state(State state);
}

package enumstatemachin;

import java.nio.ByteBuffer;

public class ContextImp implements Context {

	
	State state;

	@Override
	public State state() {
		// TODO Auto-generated method stub
		return state;
	}

	@Override
	public void state(State state) {
		this.state = state;

	}

}





你可能感兴趣的:(Java基础,代码库)