现在的位置: 首页 > 综合 > 正文

java实现多路分发

2018年12月12日 ⁄ 综合 ⁄ 共 4105字 ⁄ 字号 评论关闭

http://blog.csdn.net/godwanglong/article/details/7937668

多路分发就是指在调用a.plus(b),a和b都不知道确切类型,也能让他们正常交互。

    如果想使用两路分发,那么必须有两个方法调用,第一个方法调用决定第一个未知类型,第二个方法调用决定第二个未知类型。要利用多路分发,程序员必须为每一个类型提供给一个实际的方法调用。一般而言,程序员需要设定好某种配置,以便一个方法调用能够引出更多的方法调用,从而能在这个过程中处理多个类型。

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

[java] view
plain
copy

  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对象的具体类型了。

用上述方法,就能避免 if else的书写和获取对象具体类型的方法

这种方法的精妙之处在于,通过调用 item1的compete方法,实现对item1的类型的分发,而在item1的compete方法中,用通过调用item2的eval方法,将自身this昨晚参数,实现了Item2中eval方法的分发

使用EnumMap分发:


[java] view
plain
copy

  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.class20);  
  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. }  

抱歉!评论已关闭.