java实现多路分发

 多路分发就是指在调用a.plus(b),a和b都不知道确切类型,也能让他们正常交互。
    如果想使用两路分发,那么必须有两个方法调用,第一个方法调用决定第一个未知类型,第二个方法调用决定第二个未知类型。要利用多路分发,程序员必须为每一个类型提供给一个实际的方法调用。一般而言,程序员需要设定好某种配置,以便一个方法调用能够引出更多的方法调用,从而能在这个过程中处理多个类型。

   下面是个“石头 剪刀 布”(RoShamBo)游戏的例子 (from: thinking in java):

 
  1. public enum Outcome { WIN, LOSE, DRAW } ///:~

  2.  
  3.  
  4. interface Item {

  5. Outcome compete(Item it);

  6.  
  7. Outcome eval(Paper p);

  8.  
  9. Outcome eval(Scissors s);

  10.  
  11. Outcome eval(Rock r);

  12. }

  13.  
  14. class Paper implements Item {

  15. public Outcome compete(Item it) {

  16. return it.eval(this);

  17. }

  18.  
  19. public Outcome eval(Paper p) {

  20. return DRAW;

  21. }

  22.  
  23. public Outcome eval(Scissors s) {

  24. return WIN;

  25. }

  26.  
  27. public Outcome eval(Rock r) {

  28. return LOSE;

  29. }

  30.  
  31. public String toString() {

  32. return "Paper";

  33. }

  34. }

  35.  
  36. class Scissors implements Item {

  37. public Outcome compete(Item it) {

  38. return it.eval(this);

  39. }

  40.  
  41. public Outcome eval(Paper p) {

  42. return LOSE;

  43. }

  44.  
  45. public Outcome eval(Scissors s) {

  46. return DRAW;

  47. }

  48.  
  49. public Outcome eval(Rock r) {

  50. return WIN;

  51. }

  52.  
  53. public String toString() {

  54. return "Scissors";

  55. }

  56. }

  57.  
  58. class Rock implements Item {

  59. public Outcome compete(Item it) {

  60. return it.eval(this);

  61. }

  62.  
  63. public Outcome eval(Paper p) {

  64. return WIN;

  65. }

  66.  
  67. public Outcome eval(Scissors s) {

  68. return LOSE;

  69. }

  70.  
  71. public Outcome eval(Rock r) {

  72. return DRAW;

  73. }

  74.  
  75. public String toString() {

  76. return "Rock";

  77. }

  78. }

  79.  
  80. public class RoShamBo1 {

  81. static final int SIZE = 20;

  82. private static Random rand = new Random(47);

  83.  
  84. public static Item newItem() {

  85. switch (rand.nextInt(3)) {

  86. default:

  87. case 0:

  88. return new Scissors();

  89. case 1:

  90. return new Paper();

  91. case 2:

  92. return new Rock();

  93. }

  94. }

  95.  
  96. public static void match(Item a, Item b) {

  97. System.out.println(a + " vs. " + b + ": " + a.compete(b));

  98. }

  99.  
  100. public static void main(String[] args) {

  101. for (int i = 0; i < SIZE; i++)

  102. match(newItem(), newItem());

  103. }

  104. }

RoshamBol.match()有2个item参数,通关过Item.compete()方法开始2路分发,要判定a的类型,分发机制会在a的实际类型的compete()内部起到分发作用。compete()方法通关过eval()来为另一个类型实现第二次分发, 将自身(this)作为参数调用eval(),能够调用重载过的eval()方法,这能够保留第一次分发的类型信息,第二次分发完成时,就能知道两个Item对象的具体类型了。

使用EnumMap分发:

 
  1. enum RoShamBo5 implements Competitor<RoShamBo5> {

  2. PAPER, SCISSORS, ROCK;

  3. static EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>> table = new EnumMap<RoShamBo5, EnumMap<RoShamBo5, Outcome>>(

  4. RoShamBo5.class);

  5.  
  6. static {

  7. for (RoShamBo5 it : RoShamBo5.values())

  8. table.put(it, new EnumMap<RoShamBo5, Outcome>(RoShamBo5.class));

  9. initRow(PAPER, DRAW, LOSE, WIN);

  10. initRow(SCISSORS, WIN, DRAW, LOSE);

  11. initRow(ROCK, LOSE, WIN, DRAW);

  12. }

  13.  
  14. static void initRow(RoShamBo5 it, Outcome vPAPER, Outcome vSCISSORS,

  15. Outcome vROCK) {

  16. EnumMap<RoShamBo5, Outcome> row = RoShamBo5.table.get(it);

  17. row.put(RoShamBo5.PAPER, vPAPER);

  18. row.put(RoShamBo5.SCISSORS, vSCISSORS);

  19. row.put(RoShamBo5.ROCK, vROCK);

  20. }

  21.  
  22. public Outcome compete(RoShamBo5 it) {

  23. return table.get(this).get(it);

  24. }

  25.  
  26. public static void main(String[] args) {

  27. RoShamBo.play(RoShamBo5.class, 20);

  28. }

  29. }

  30.  
  31. public class RoShamBo {

  32. public static <T extends Competitor<T>> void match(T a, T b) {

  33. System.out.println(a + " vs. " + b + ": " + a.compete(b));

  34. }

  35.  
  36. public static <T extends Enum<T> & Competitor<T>> void play(

  37. Class<T> rsbClass, int size) {

  38. for (int i = 0; i < size; i++)

  39. match(Enums.random(rsbClass), Enums.random(rsbClass));

  40. }

  41. }

猜你喜欢

转载自blog.csdn.net/xjk201/article/details/81703421