《Java编程思想》这本书已经看到19章枚举,之前的很多难点被我略过了。在此章学到了新概念,多路分发。先说说单路分发: Java只支持单路分发,即如果要执行的操作包含多个不确定的类型类型对象时,Java只能处理其中一个的类型。N个未知类型需要N个方法调用以确定其类型即分发。所以编程思想中的多路分发严格讲应该叫“伪多路分发”即多次单路分发。单路分发实质上是多态特性的一种体现。
举个梨子:例如有A、B、C、三种类型a.compete(b),a、b的类型未知,执行此句时只能确定a的类型
代码为证:
package com.houjun.enum1;
import java.util.Random;
/**
* @Author: HouJun
* @Date: 2019/10/8 17:29
* @Description: 多路分发例子
* @version: 1.0
*/
enum Outcome {
WIN, LOSE, DRAW;
}
interface Item {
// Outcome compete(Item it);//完成方法
Outcome eval(Paper p);
Outcome eval(Scissors s);
Outcome eval(Rock r);
Outcome eval(Item r);
}
class Paper implements Item {
// @Override
// public Outcome compete(Item item) {
// return item.eval(this);
// }
@Override
public Outcome eval(Paper p) {
return Outcome.DRAW;
}
@Override
public Outcome eval(Scissors s) {
return Outcome.LOSE;
}
@Override
public Outcome eval(Rock r) {
return Outcome.WIN;
}
@Override
public Outcome eval(Item r) {
System.out.println(r.getClass().getName());
System.out.println("c");
return null;
}
}
class Scissors implements Item {
// @Override
// public Outcome compete(Item it) {
// return it.eval(this);
// }
@Override
public Outcome eval(Paper p) {
return Outcome.LOSE;
}
@Override
public Outcome eval(Scissors s) {
return Outcome.DRAW;
}
@Override
public Outcome eval(Rock r) {
return Outcome.WIN;
}
@Override
public Outcome eval(Item r) {
System.out.println(r.getClass().getName());
System.out.println("b");
return null;
}
}
class Rock implements Item {
// @Override
// public Outcome compete(Item it) {
// return it.eval(this);
// }
@Override
public Outcome eval(Paper p) {
return Outcome.LOSE;
}
@Override
public Outcome eval(Scissors s) {
return Outcome.WIN;
}
@Override
public Outcome eval(Rock r) {
return Outcome.DRAW;
}
@Override
public Outcome eval(Item r) {
// if ( r instanceof Rock){
// return this.eval(new Rock());
// }
// if ( r instanceof Scissors){
// return this.eval(new Scissors());
// }if ( r instanceof Paper){
// return this.eval(new Paper());
// }
System.out.println("a");
return null;
}
}
public class RoShaamBo {
static final int SIZE = 20;
private static Random random = new Random(47);
public static Item newItem() {
switch (random.nextInt(3)) {
default:
case 0:
return new Scissors();
case 1:
return new Paper();
case 2:
return new Rock();
}
}
public static void match(Item a, Item b) {
System.out.println(a.getClass().getName() + " vs " + b.getClass().getName() + " ; " + a.eval(b));
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
match(newItem(), newItem());
}
}
}
上面match()方法中可以正确调用a.eval(b),确定a的类型,而b则不去确定其具体类型,一直使用其基类Item类型。传统的方法是重载eval(),在其中使用instanceOf来判断b的类型然后指定调用方法,这样很繁琐。书中给出了这种再次使用单路分发的方式,巧妙的解决了这个问题。代码为证:
// enums/Outcome.java
package enums;
public enum Outcome { WIN, LOSE, DRAW }
// enums/RoShamBo1.java
// Demonstration of multiple dispatching
// {java enums.RoShamBo1}
package enums;
import java.util.*;
import static enums.Outcome.*;
interface Item {
Outcome compete(Item it);
Outcome eval(Paper p);
Outcome eval(Scissors s);
Outcome eval(Rock r);
}
class Paper implements Item {
@Override
public Outcome compete(Item it) {
return it.eval(this);
}
@Override
public Outcome eval(Paper p) { return DRAW; }
@Override
public Outcome eval(Scissors s) { return WIN; }
@Override
public Outcome eval(Rock r) { return LOSE; }
@Override
public String toString() { return "Paper"; }
}
class Scissors implements Item {
@Override
public Outcome compete(Item it) {
return it.eval(this);
}
@Override
public Outcome eval(Paper p) { return LOSE; }
@Override
public Outcome eval(Scissors s) { return DRAW; }
@Override
public Outcome eval(Rock r) { return WIN; }
@Override
public String toString() { return "Scissors"; }
}
class Rock implements Item {
@Override
public Outcome compete(Item it) {
return it.eval(this);
}
@Override
public Outcome eval(Paper p) { return WIN; }
@Override
public Outcome eval(Scissors s) { return LOSE; }
@Override
public Outcome eval(Rock r) { return DRAW; }
@Override
public String toString() { return "Rock"; }
}
public class RoShamBo1 {
static final int SIZE = 20;
private static Random rand = new Random(47);
public static Item newItem() {
switch(rand.nextInt(3)) {
default:
case 0: return new Scissors();
case 1: return new Paper();
case 2: return new Rock();
}
}
public static void match(Item a, Item b) {
System.out.println(
a + " vs. " + b + ": " + a.compete(b));
}
public static void main(String[] args) {
for(int i = 0; i < SIZE; i++)
match(newItem(), newItem());
}
}