java基础总结 --- enum枚举实现多路分发 石头、剪刀、布游戏示例

 多路分发:
当你处理多种交互类型时,程序可能会变得相当杂乱。举例来说,如果一个系统要分析
和执行数学表达式。我们可能会声明Number.plus(Number)、Number.mulitple(Number)等等,

其中Number是各种数字对象的超类。然而,当你声明a.plus(b)时,你并不知道a或者b的确切类型,那你如何能让它们正确交互呢?

你可能从未思考过这个问题的答案。Java只支持单路分发。也就是说,如果要执行的操作包含了不止一个类型

   未知的对象时,那么Java的动态绑定机制只能处理其中一个的类型。这就无法解决我们上面提到的问题。所以,
   你必须自己来判断其他的类型,从而实现自己的动态绑定行为。
  
   解决上面问题的办法就是多路分发。多态只能发生在方法调用时,所以,如果你想使用两路分发,那么就必须有两个
   方法调用:
       第一个方法调用决定第二个未知类型,第二个方法调用决定第二个未知类型。
       要利用多路分发,程序员必须为每一个类型提供一个实际的方法调用,如果你要处理两个不同的类型体系,就需要
     为每个类型体系执行一个方法调用。
         一般而言,程序员需要由设定好的某种配置,以便一个方法调用能够引出更多的方法调用,从而能够在这个过程中
     处理多种类型。

     为了达到这种效果,我们需要与多个方法一同工作:因为每个分发都需要一个方法调用。     


下面使用多种方法实现了石头、剪刀 、布 游戏,其中就使用了enum分发机制

猜拳第一种实现:

package com.zghw.base.enumx;

import static com.zghw.base.enumx.Outcome.*;

import java.util.Random;

/**
 * 使用接口和度哟个子类进行多路分发
 * 
 * 石头、剪刀、布 游戏
 * 
 * @author zghw
 *
 */
//Item是这几种类型的接口,将会被用作多路分发
interface Item {
	//调用Item.compete()方法开始两路分发
	Outcome compete(Item item);

	Outcome eval(Rock rock);

	Outcome eval(Scissors scissors);

	Outcome eval(Paper paper);

}

class Rock implements Item {
	//调用Item.compete()方法开始两路分发
	//compete()方法通过调用eval()来为另一个类型实现第二次分发。
	//将自身(this)作为参数调用eval(),能够调用重载过的eval()方法,
	//能够保留第一次分发的类型信息。当第二次分发完成时,你就能够知道两个Item对象的具体类型了。
	@Override
	public Outcome compete(Item item) {
		return item.eval(this);
	}

	@Override
	public Outcome eval(Rock rock) {
		return DRAW;
	}

	@Override
	public Outcome eval(Scissors scissors) {
		return LOSE;
	}

	@Override
	public Outcome eval(Paper paper) {
		return WIN;
	}

	@Override
	public String toString() {
		return "Rock";
	}
}

class Scissors implements Item {
	@Override
	public Outcome compete(Item item) {
		return item.eval(this);
	}

	@Override
	public Outcome eval(Rock rock) {
		return WIN;
	}

	@Override
	public Outcome eval(Scissors scissors) {
		return DRAW;
	}

	@Override
	public Outcome eval(Paper paper) {
		return LOSE;
	}

	@Override
	public String toString() {
		return "Scissors";
	}
}

class Paper implements Item {

	@Override
	public Outcome compete(Item item) {
		return item.eval(this);
	}

	@Override
	public Outcome eval(Rock rock) {
		return LOSE;
	}

	@Override
	public Outcome eval(Scissors scissors) {
		return WIN;
	}

	@Override
	public Outcome eval(Paper paper) {
		return DRAW;
	}

	@Override
	public String toString() {
		return "Paper";
	}
}

public class RoShamBo1 {

	public static void play(Item a, Item b) {
		//调用Item.compete()方法开始两路分发。要判断a的类型,
		//分发机制会在a的时机类型的compete()内部起到分发的作用。
		System.out.println(a + " vs " + b + " == " + a.compete(b));
	}

	static Random random = new Random(47);

	public static Item newItem() {
		switch (random.nextInt(3)) {
		case 0:
			return new Rock();
		case 1:
			return new Scissors();
		case 2:
			return new Paper();
		default:
			return null;
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 20; i++) {
			play(newItem(), newItem());
		}
	}

}
猜拳第二种实现:

package com.zghw.base.enumx;

public class RoShamBo {

	/**
	 * 玩游戏
	 * @param ec
	 * @param size
	 */
	public static <T extends Enum<T> & Competitor<T>> void play(Class<T> ec,int size){
		for(int i=0;i<size;i++){
			match(Enums.next(ec),Enums.next(ec));
		}
	}
	/**
	 * 比赛
	 * @param a
	 * @param b
	 */
	public static <T extends Enum<T> & Competitor<T>> void match(T a ,T b){
		System.out.println(a + " vs " + b + " == " + a.competitor(b));
	}
}

package com.zghw.base.enumx;
/**
 * 比赛接口
 * @author zghw
 *
 * @param <T>
 */
public interface Competitor<T> {
	Outcome competitor(T t);
}

package com.zghw.base.enumx;
import static com.zghw.base.enumx.Outcome.*;
/**
 * 使用enum分发
 * 石头、剪刀、布游戏使用enum实现
 * 使用构造器来初始化每个enum实例,并以“一组”结果作为参数。
 * 这二者放在一起,形成了类似查询表的结构。
 * @author zghw
 *
 */
public enum RoShamBo2 implements Competitor<RoShamBo2> {
	ROCK(DRAW,WIN,LOSE),
	SCISSORS(LOSE,DRAW,WIN),
	PAPER(WIN,LOSE,DRAW);
	private Outcome vrock;
	private Outcome vscissors;
	private Outcome vpaper;

	private RoShamBo2(Outcome rock,Outcome scissors,Outcome paper){
		this.vrock= rock;
		this.vscissors = scissors;
		this.vpaper = paper;
	}
	@Override
	public Outcome competitor(RoShamBo2 t) {
		switch(t){
		default:
		case ROCK:
			return vrock;
		case SCISSORS:
			return vscissors;
		case PAPER:
			return vpaper;
		}
	}
	public static void main(String args[]){
		RoShamBo.play(RoShamBo2.class, 10);
	}
}
猜拳最优第三种实现:

package com.zghw.base.enumx;

import static com.zghw.base.enumx.Outcome.*;
import java.util.EnumMap;

/**
 * 使用EnumMap实现真正的两路分发
 * 石头 、剪刀、布游戏
 * @author zghw
 *
 */
public enum RoShamBo3 implements Competitor<RoShamBo3> {
	ROCK, SCISSORS, PAPER;
	static EnumMap<RoShamBo3, EnumMap<RoShamBo3, Outcome>> table = new EnumMap<RoShamBo3, EnumMap<RoShamBo3, Outcome>>(
			RoShamBo3.class);

	static {
		//初始化表结构 就像一个表格
		for (RoShamBo3 rs : RoShamBo3.values()) {
			table.put(rs, new EnumMap<RoShamBo3, Outcome>(RoShamBo3.class));
		}
		initRow(ROCK, DRAW, WIN, LOSE);
		initRow(SCISSORS, LOSE, DRAW, WIN);
		initRow(PAPER, WIN, LOSE, DRAW);
	}

	private static void initRow(RoShamBo3 rs, Outcome vrock, Outcome vscissors,
			Outcome vpaper) {
		EnumMap<RoShamBo3, Outcome> rso = table.get(rs);
		rso.put(ROCK, vrock);
		rso.put(SCISSORS, vscissors);
		rso.put(PAPER, vpaper);
		table.put(rs, rso);
	}

	@Override
	public Outcome competitor(RoShamBo3 t) {
		return table.get(this).get(t);
	}

	public static void main(String args[]) {
		RoShamBo.play(RoShamBo3.class, 10);
	}
}


你可能感兴趣的:(java基础总结 --- enum枚举实现多路分发 石头、剪刀、布游戏示例)