java只支持单路分发,如果要处理的参数包含了不知一个未知类型的对象时,那么java的动态绑定机制只能去处理一个类型。解决上面的办法就是自己去判断其他类型,从而实现自己的动态绑定。解决个问题的就是多路分发。
    一、多路分发:
    由于多态只发生在方法调用的时候,所以要是实现多路分发(以两路为列),就要有两个方法的调用,第一个方法 决定第一个未知说的类型,第二个方法决定第二个位置说的类型。

    1. package com.package19.games;
    2. import java.util.Random;
    3. class Stone implements Item{
    4. @Override
    5. public String toString() {
    6. return "石头";
    7. }
    8. @Override
    9. public Outcom compaete(Item item) {
    10. System.out.println(item+"stone");
    11. return item.eval(this);
    12. }
    13. @Override
    14. public Outcom eval(Stone stone) {
    15. System.out.println(stone);
    16. return Outcom.平局;
    17. }
    18. @Override
    19. public Outcom eval(Scissors scissors) {
    20. System.out.println(scissors);
    21. return Outcom.胜利;
    22. }
    23. @Override
    24. public Outcom eval(Cloth cloth) {
    25. System.out.println(cloth);
    26. return Outcom.失败;
    27. }//石头
    28. }
    29. class Scissors implements Item{
    30. @Override
    31. public String toString() {
    32. return "剪刀";
    33. }
    34. @Override
    35. public Outcom compaete(Item item) {
    36. System.out.println(item+"scissors");
    37. return item.eval(this);
    38. }
    39. @Override
    40. public Outcom eval(Stone stone) {
    41. System.out.println(stone);
    42. return Outcom.失败;
    43. }
    44. @Override
    45. public Outcom eval(Scissors scissors) {
    46. System.out.println(scissors);
    47. return Outcom.平局;
    48. }
    49. @Override
    50. public Outcom eval(Cloth cloth) {
    51. System.out.println(cloth);
    52. return Outcom.胜利;
    53. }//剪刀
    54. }
    55. class Cloth implements Item{
    56. @Override
    57. public Outcom compaete(Item item) {
    58. System.out.println(item+"cloth");
    59. return item.eval(this);
    60. }
    61. @Override
    62. public Outcom eval(Stone stone) {
    63. System.out.println(stone);
    64. return Outcom.胜利;
    65. }
    66. @Override
    67. public Outcom eval(Scissors scissors) {
    68. System.out.println(scissors);
    69. return Outcom.失败;
    70. }
    71. @Override
    72. public Outcom eval(Cloth cloth) {
    73. System.out.println(cloth);
    74. return Outcom.平局;
    75. }
    76. @Override
    77. public String toString() {
    78. return "布";
    79. }
    80. }
    81. public class Rondem_One {
    82. static final int SIZE=20;
    83. static Random random = new Random();
    84. public static Item gaems(){
    85. switch (random.nextInt(3)){
    86. default:
    87. case 0:
    88. return new Stone();
    89. case 1:
    90. return new Scissors();
    91. case 2:
    92. return new Cloth();
    93. }
    94. }
    95. public static void methods(Item item1,Item item2){
    96. Outcom outcom = item1.compaete(item2);
    97. System.out.println(item1+" VS "+item2+":"+ outcom);
    98. }
    99. public static void main(String[] args) {
    100. Item gaems = gaems();
    101. Item gaems1 = gaems();
    102. methods(gaems,gaems1);
    103. }
    104. }

    上述石头剪刀布的列子就是一个多路分发,在methods(Item item1,Item item2)方法中有两个未知对象的类型,调用item1.compaete(item2),通过java的单路分发方法可以确定第一个对象的类型,然后每个类型的内部又有一个 compaete(Item item) 方法来确定第二个对象的类型。
    二、使用enum实现分发
    使用enum也可以做到分发。
    1.产生随机enum实例的方法

    1. public class Enums {
    2. private static Random ran=new Random();
    3. //1.通过一个方法对返回的获取class对象,然后在通过random()方法处理返回的数组
    4. public static <T extends Enum<T>> T random(Class<T> cla){
    5. return random(cla.getEnumConstants());//getEnumConstants()拿到enum类中的所有enum实例
    6. }
    7. //处理返回的数组
    8. public static <T> T random(T[] values){
    9. return values[ran.nextInt(values.length)];
    10. }
    11. //2.直接在方法内部一次进行完毕
    12. public static <T extends Enum<T>> T randoms(Class<T> s){
    13. T[] constants = s.getEnumConstants();
    14. T t=constants[ran.nextInt(constants.length)];
    15. return t;
    16. }
    17. }

    2.编写用于对象之间比较的方法接口

    1. public interface Competitor<T extends Competitor<T>> {
    2. Outcom compete(T competitor);
    3. }

    3.编写具体实现

    1. public enum RoShamBo2 implements Competitor<RoShamBo2> {
    2. 纸(Outcom.平局, Outcom.失败, Outcom.胜利),
    3. 剪刀(Outcom.胜利, Outcom.平局, Outcom.失败),
    4. 石头(Outcom.失败, Outcom.胜利, Outcom.平局);
    5. private Outcom o1, o2, o3;
    6. RoShamBo2(Outcom paper, Outcom o2, Outcom o3) {
    7. o1 = paper;
    8. this.o2 = o2;
    9. this.o3 = o3;
    10. }
    11. @Override
    12. public Outcom compete(RoShamBo2 competitor) {
    13. switch (competitor) {
    14. default:
    15. case 纸:
    16. return o1;
    17. case 剪刀:
    18. return o2;
    19. case 石头:
    20. return o3;
    21. }
    22. }
    23. RoShamBo.play(RoShamBo2.class, 20);
    24. }
    25. }

    在上述程序中,通过enum实现了多路分发。
    1.1通过构造器为每个实例添加结果信息

    1. public enum RoShamBo2 implements Competitor<RoShamBo2> {
    2. 纸(Outcom.平局, Outcom.失败, Outcom.胜利),
    3. 剪刀(Outcom.胜利, Outcom.平局, Outcom.失败),
    4. 石头(Outcom.失败, Outcom.胜利, Outcom.平局);
    5. private Outcom o1, o2, o3;
    6. RoShamBo2(Outcom paper, Outcom o2, Outcom o3) {
    7. o1 = paper;
    8. this.o2 = o2;
    9. this.o3 = o3;
    10. }

    1.1通过enum实现接口中的compete方法、用于两个enum实例进行比较。并返回结果

    1. public Outcom compete(RoShamBo2 competitor) {
    2. switch (competitor) {
    3. default:
    4. case 纸:
    5. return o1;
    6. case 剪刀:
    7. return o2;
    8. case 石头:
    9. return o3;
    10. }

    1.3编写RoShamBo类来进行随机产实例和进行分发

    1. public class RoShamBo {
    2. public static <T extends Competitor<T>>
    3. void match(T a, T b) {
    4. System.out.println(a + " vs. " + b + ": " + a.compete(b));
    5. }
    6. public static <T extends Enum<T> & Competitor<T>>void play(Class<T> rsbClass, int size) {
    7. for(int i = 0; i < size; i++)
    8. match(Enums.random(rsbClass),Enums.random(rsbClass));
    9. }
    10. }
    1. 第一个enum实例将调用competer方法,并且将第二个enum实例参数与case想比较同时。由于每个实例都有comperter方法所以只需要在构造器赋值的时候赋予不同的值即可。

    三、使用EnumMap进行分发
    使用EnumMap能够实现真正的两路分发

    1. public class RoShamBo {
    2. public static <T extends Competitor<T>>
    3. void match(T a, T b) {
    4. System.out.println(
    5. a + " vs. " + b + ": " + a.compete(b));
    6. }
    7. public static <T extends Enum<T> & Competitor<T>>
    8. void play(Class<T> rsbClass, int size) {
    9. for(int i = 0; i < size; i++)
    10. match(
    11. Enums.random(rsbClass),Enums.random(rsbClass));
    12. }
    13. }
    14. public interface Competitor<T extends Competitor<T>> {
    15. Outcome compete(T competitor);
    16. }
    17. public class Enums {
    18. private static Random rand = new Random(47);
    19. public static <T extends Enum<T>> T random(Class<T> ec) {
    20. return random(ec.getEnumConstants());
    21. }
    22. public static <T> T random(T[] values) {
    23. return values[rand.nextInt(values.length)];
    24. }
    25. }
    1. enum RoShamBo5 implements Competitor<RoShamBo5> {
    2. PAPER, SCISSORS, ROCK;
    3. static EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>>
    4. table = new EnumMap<RoShamBo5,
    5. EnumMap<RoShamBo5,Outcome>>(RoShamBo5.class);
    6. static {
    7. for(RoShamBo5 it : RoShamBo5.values())
    8. table.put(it,
    9. new EnumMap<RoShamBo5,Outcome>(RoShamBo5.class));
    10. initRow(PAPER, DRAW, LOSE, WIN);
    11. initRow(SCISSORS, WIN, DRAW, LOSE);
    12. initRow(ROCK, LOSE, WIN, DRAW);
    13. }
    14. static void initRow(RoShamBo5 it,
    15. Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {
    16. EnumMap<RoShamBo5,Outcome> row =
    17. RoShamBo5.table.get(it);
    18. row.put(RoShamBo5.PAPER, vPAPER);
    19. row.put(RoShamBo5.SCISSORS, vSCISSORS);
    20. row.put(RoShamBo5.ROCK, vROCK);
    21. }
    22. public Outcome compete(RoShamBo5 it) {
    23. return table.get(this).get(it);
    24. }
    25. public static void main(String[] args) {
    26. RoShamBo.play(RoShamBo5.class, 20);
    27. }
    28. }