其中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); } }