多路分发:
当你处理多种交互类型时,程序可能会变得相当杂乱。举例来说,如果一个系统要分析
和执行数学表达式。我们可能会声明Number.plus(Number)、Number.mulitple(Number)等等,
你必须自己来判断其他的类型,从而实现自己的动态绑定行为。
解决上面问题的办法就是多路分发。多态只能发生在方法调用时,所以,如果你想使用两路分发,那么就必须有两个
方法调用:
第一个方法调用决定第二个未知类型,第二个方法调用决定第二个未知类型。
要利用多路分发,程序员必须为每一个类型提供一个实际的方法调用,如果你要处理两个不同的类型体系,就需要
为每个类型体系执行一个方法调用。
一般而言,程序员需要由设定好的某种配置,以便一个方法调用能够引出更多的方法调用,从而能够在这个过程中
处理多种类型。
当你处理多种交互类型时,程序可能会变得相当杂乱。举例来说,如果一个系统要分析
和执行数学表达式。我们可能会声明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);
}
}