java只支持单路分发,如果要处理的参数包含了不知一个未知类型的对象时,那么java的动态绑定机制只能去处理一个类型。解决上面的办法就是自己去判断其他类型,从而实现自己的动态绑定。解决个问题的就是多路分发。
一、多路分发:
由于多态只发生在方法调用的时候,所以要是实现多路分发(以两路为列),就要有两个方法的调用,第一个方法 决定第一个未知说的类型,第二个方法决定第二个位置说的类型。
package com.package19.games;
import java.util.Random;
class Stone implements Item{
@Override
public String toString() {
return "石头";
}
@Override
public Outcom compaete(Item item) {
System.out.println(item+"stone");
return item.eval(this);
}
@Override
public Outcom eval(Stone stone) {
System.out.println(stone);
return Outcom.平局;
}
@Override
public Outcom eval(Scissors scissors) {
System.out.println(scissors);
return Outcom.胜利;
}
@Override
public Outcom eval(Cloth cloth) {
System.out.println(cloth);
return Outcom.失败;
}//石头
}
class Scissors implements Item{
@Override
public String toString() {
return "剪刀";
}
@Override
public Outcom compaete(Item item) {
System.out.println(item+"scissors");
return item.eval(this);
}
@Override
public Outcom eval(Stone stone) {
System.out.println(stone);
return Outcom.失败;
}
@Override
public Outcom eval(Scissors scissors) {
System.out.println(scissors);
return Outcom.平局;
}
@Override
public Outcom eval(Cloth cloth) {
System.out.println(cloth);
return Outcom.胜利;
}//剪刀
}
class Cloth implements Item{
@Override
public Outcom compaete(Item item) {
System.out.println(item+"cloth");
return item.eval(this);
}
@Override
public Outcom eval(Stone stone) {
System.out.println(stone);
return Outcom.胜利;
}
@Override
public Outcom eval(Scissors scissors) {
System.out.println(scissors);
return Outcom.失败;
}
@Override
public Outcom eval(Cloth cloth) {
System.out.println(cloth);
return Outcom.平局;
}
@Override
public String toString() {
return "布";
}
}
public class Rondem_One {
static final int SIZE=20;
static Random random = new Random();
public static Item gaems(){
switch (random.nextInt(3)){
default:
case 0:
return new Stone();
case 1:
return new Scissors();
case 2:
return new Cloth();
}
}
public static void methods(Item item1,Item item2){
Outcom outcom = item1.compaete(item2);
System.out.println(item1+" VS "+item2+":"+ outcom);
}
public static void main(String[] args) {
Item gaems = gaems();
Item gaems1 = gaems();
methods(gaems,gaems1);
}
}
上述石头剪刀布的列子就是一个多路分发,在methods(Item item1,Item item2)方法中有两个未知对象的类型,调用item1.compaete(item2),通过java的单路分发方法可以确定第一个对象的类型,然后每个类型的内部又有一个 compaete(Item item) 方法来确定第二个对象的类型。
二、使用enum实现分发
使用enum也可以做到分发。
1.产生随机enum实例的方法
public class Enums {
private static Random ran=new Random();
//1.通过一个方法对返回的获取class对象,然后在通过random()方法处理返回的数组
public static <T extends Enum<T>> T random(Class<T> cla){
return random(cla.getEnumConstants());//getEnumConstants()拿到enum类中的所有enum实例
}
//处理返回的数组
public static <T> T random(T[] values){
return values[ran.nextInt(values.length)];
}
//2.直接在方法内部一次进行完毕
public static <T extends Enum<T>> T randoms(Class<T> s){
T[] constants = s.getEnumConstants();
T t=constants[ran.nextInt(constants.length)];
return t;
}
}
2.编写用于对象之间比较的方法接口
public interface Competitor<T extends Competitor<T>> {
Outcom compete(T competitor);
}
3.编写具体实现
public enum RoShamBo2 implements Competitor<RoShamBo2> {
纸(Outcom.平局, Outcom.失败, Outcom.胜利),
剪刀(Outcom.胜利, Outcom.平局, Outcom.失败),
石头(Outcom.失败, Outcom.胜利, Outcom.平局);
private Outcom o1, o2, o3;
RoShamBo2(Outcom paper, Outcom o2, Outcom o3) {
o1 = paper;
this.o2 = o2;
this.o3 = o3;
}
@Override
public Outcom compete(RoShamBo2 competitor) {
switch (competitor) {
default:
case 纸:
return o1;
case 剪刀:
return o2;
case 石头:
return o3;
}
}
RoShamBo.play(RoShamBo2.class, 20);
}
}
在上述程序中,通过enum实现了多路分发。
1.1通过构造器为每个实例添加结果信息
public enum RoShamBo2 implements Competitor<RoShamBo2> {
纸(Outcom.平局, Outcom.失败, Outcom.胜利),
剪刀(Outcom.胜利, Outcom.平局, Outcom.失败),
石头(Outcom.失败, Outcom.胜利, Outcom.平局);
private Outcom o1, o2, o3;
RoShamBo2(Outcom paper, Outcom o2, Outcom o3) {
o1 = paper;
this.o2 = o2;
this.o3 = o3;
}
1.1通过enum实现接口中的compete方法、用于两个enum实例进行比较。并返回结果
public Outcom compete(RoShamBo2 competitor) {
switch (competitor) {
default:
case 纸:
return o1;
case 剪刀:
return o2;
case 石头:
return o3;
}
1.3编写RoShamBo类来进行随机产实例和进行分发
public class RoShamBo {
public static <T extends Competitor<T>>
void match(T a, T b) {
System.out.println(a + " vs. " + b + ": " + a.compete(b));
}
public static <T extends Enum<T> & Competitor<T>>void play(Class<T> rsbClass, int size) {
for(int i = 0; i < size; i++)
match(Enums.random(rsbClass),Enums.random(rsbClass));
}
}
第一个enum实例将调用competer方法,并且将第二个enum实例参数与case想比较同时。由于每个实例都有comperter方法所以只需要在构造器赋值的时候赋予不同的值即可。
三、使用EnumMap进行分发
使用EnumMap能够实现真正的两路分发
public class RoShamBo {
public static <T extends Competitor<T>>
void match(T a, T b) {
System.out.println(
a + " vs. " + b + ": " + a.compete(b));
}
public static <T extends Enum<T> & Competitor<T>>
void play(Class<T> rsbClass, int size) {
for(int i = 0; i < size; i++)
match(
Enums.random(rsbClass),Enums.random(rsbClass));
}
}
public interface Competitor<T extends Competitor<T>> {
Outcome compete(T competitor);
}
public class Enums {
private static Random rand = new Random(47);
public static <T extends Enum<T>> T random(Class<T> ec) {
return random(ec.getEnumConstants());
}
public static <T> T random(T[] values) {
return values[rand.nextInt(values.length)];
}
}
enum RoShamBo5 implements Competitor<RoShamBo5> {
PAPER, SCISSORS, ROCK;
static EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>>
table = new EnumMap<RoShamBo5,
EnumMap<RoShamBo5,Outcome>>(RoShamBo5.class);
static {
for(RoShamBo5 it : RoShamBo5.values())
table.put(it,
new EnumMap<RoShamBo5,Outcome>(RoShamBo5.class));
initRow(PAPER, DRAW, LOSE, WIN);
initRow(SCISSORS, WIN, DRAW, LOSE);
initRow(ROCK, LOSE, WIN, DRAW);
}
static void initRow(RoShamBo5 it,
Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {
EnumMap<RoShamBo5,Outcome> row =
RoShamBo5.table.get(it);
row.put(RoShamBo5.PAPER, vPAPER);
row.put(RoShamBo5.SCISSORS, vSCISSORS);
row.put(RoShamBo5.ROCK, vROCK);
}
public Outcome compete(RoShamBo5 it) {
return table.get(this).get(it);
}
public static void main(String[] args) {
RoShamBo.play(RoShamBo5.class, 20);
}
}