疾风步行者

V1

2022/05/29阅读:18主题:兰青

多路分发

什么是多路分发

比如要执行一个通用的数学计算,计算表达式可能是a.plus(b),但是不知道a和b的具体类型,如果按照普通的做法,需要对a和b做两次类型判断,这种写法不够优雅。

好的解决办法就是使用多路分发,一共5种方式,最优方案在最后,下面看一个“石头剪子布”的示例。

方法重载分发

这种就是根据Java的多态特性+方法重载,a使用多态来确定类型,b根据多个重载方法确定类型

package onJava.enums.multi;

/**
 * 分发类型接口
 */

public interface Item {
    Outcome compete(Item it);
    Outcome eval(Paper p);
    Outcome eval(Scissors s);
    Outcome eval(Rock r);
}

package onJava.enums.multi;

/**
 * 结果枚举
 */

public enum Outcome {

    WIN, LOSE, DRAW
}

package onJava.enums.multi;
import static onJava.enums.multi.Outcome.*;

/**
 * 布
 */

public 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";
    }
}

-----------------------------分割线--------------------------------


package onJava.enums.multi;
import onJava.enums.multi.Outcome.*;

/**
 * 石头
 */

import static onJava.enums.multi.Outcome.*;

public 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";
    }
}

-----------------------------分割线--------------------------------


package onJava.enums.multi;
import onJava.enums.multi.Outcome.*;

import static onJava.enums.multi.Outcome.*;

/**
 * 剪刀
 */

public 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";
    }
}

-----------------------------分割线--------------------------------


package onJava.enums.multi;

import java.util.Random;

/**
 * 测试类
 */

public class Ro1 {

    private static Random random = new Random(47);

    static final  int SIZE = 20;

    /**
     * 随机生产
     * @return
     */

    public static Item newItem() {
        switch (random.nextInt(3)) {
            default:
            case 0return new Scissors();
            case 1return new Paper();
            case 2return new Rock();
        }
    }

    /**
     * 两个参数比较
     * @param a
     * @param b
     */

    public static void match(Item a, Item b) {
        System.out.println(a + " VS " + b + ":" + a.compete(b));
    }

    public static void main(String[] args) {
        //随机生成20次记录
        for (int i = 0; i < SIZE; i++) {
            match(newItem(), newItem());
        }
    }
}

输出结果:

Rock VS Rock:DRAW
Paper VS Rock:WIN
Paper VS Rock:WIN
Paper VS Rock:WIN
Scissors VS Paper:WIN
Scissors VS Scissors:DRAW
Scissors VS Paper:WIN
Rock VS Paper:LOSE
Paper VS Paper:DRAW
Rock VS Paper:LOSE
Paper VS Scissors:LOSE
Paper VS Scissors:LOSE
Rock VS Scissors:WIN
Rock VS Paper:LOSE
Paper VS Rock:WIN
Scissors VS Paper:WIN
Paper VS Scissors:LOSE
Paper VS Scissors:LOSE
Paper VS Scissors:LOSE
Paper VS Scissors:LOSE

枚举分发

package onJava.enums.multi;

/**
 * 比较器
 * @param <T>
 */

public interface Competitor<T extends Competitor<T>> {

    Outcome compete(T competitor);
}

-----------------------------分割线--------------------------------

package onJava.enums.multi;
import static onJava.enums.multi.Outcome.*;

/**
 * 枚举分发,实现热比较器compete
 */

public enum Ro2 implements  Competitor<Ro2> {

    //3个值,分别为 “布”与“布”的胜负,“布”与“剪刀”胜负,“布”与“石头”胜负
    PAPER(DRAW, LOSE, WIN),
    //剪刀与布、剪刀、石头胜负
    SCISSORS(WIN,DRAW, LOSE),
    //石头与布,剪刀、石头胜负
    ROCK(LOSE, WIN, DRAW)
        ;


    private Outcome vPAPER, vSCISSORS, vROCK;

    Ro2(Outcome paper, Outcome scissors, Outcome rock) {
        this.vPAPER = paper;
        this.vSCISSORS = scissors;
        this.vROCK = rock;
    }

    @Override
    public Outcome compete(Ro2 it) {
        switch (it) {
            case PAPER: return vPAPER;
            case SCISSORS: return vSCISSORS;
            case ROCK: return vROCK;
            default:
        }
        return null;
    }
    
    public static void main(String[] args) {
        Ro.play(Ro2.class, 20);
    }
}

-----------------------------分割线--------------------------------


package onJava.enums.multi;

import java.util.Random;

public class Ro {
    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));
        }
    }

}

-----------------------------分割线--------------------------------

/**
 * 枚举获取随机值
 */

class Enums {
    private static Random rand = new Random(47);
    public static
    <T extends Enum<T>> random(Class<T> ec) {
        return random(ec.getEnumConstants());
    }
    public static <T> random(T[] values) {
        return values[rand.nextInt(values.length)];
    }
}


输出:

ROCK VS ROCK:DRAW
SCISSORS VS ROCK:LOSE
SCISSORS VS ROCK:LOSE
SCISSORS VS ROCK:LOSE
PAPER VS SCISSORS:LOSE
PAPER VS PAPER:DRAW
PAPER VS SCISSORS:LOSE
ROCK VS SCISSORS:WIN
SCISSORS VS SCISSORS:DRAW
ROCK VS SCISSORS:WIN
SCISSORS VS PAPER:WIN
SCISSORS VS PAPER:WIN
ROCK VS PAPER:LOSE
ROCK VS SCISSORS:WIN
SCISSORS VS ROCK:LOSE
PAPER VS SCISSORS:LOSE
SCISSORS VS PAPER:WIN
SCISSORS VS PAPER:WIN
SCISSORS VS PAPER:WIN
SCISSORS VS PAPER:WIN

常量特定方法分发

package onJava.enums.multi;
import onJava.enums.multi.Enums.*;

import static onJava.enums.multi.Outcome.*;

/**
 * 枚举类,实现比较器接口,通过switch来判断传入参数
 */

public enum Ro3 implements Competitor<Ro3> {

    PAPER{
        @Override
        public Outcome compete(Ro3 it) {
            switch (it) {
                case PAPER: return DRAW;
                case SCISSORS:return LOSE;
                case ROCK: return WIN;
                defaultreturn null;
            }
        }
    },
    SCISSORS {
        @Override
        public Outcome compete(Ro3 it) {
            switch (it) {
                case PAPER: return WIN;
                case SCISSORS: return DRAW;
                case ROCK: return LOSE;
                defaultreturn null;
            }
        }
    },
    ROCK {
        @Override
        public Outcome compete(Ro3 it) {
            switch (it) {
                case PAPER: return LOSE;
                case SCISSORS: return WIN;
                case ROCK: return DRAW;
                defaultreturn null;
            }
        }
    }
    ;


    @Override
    public abstract Outcome compete(Ro3 competitor);

    public static void main(String[] args) {
        Ro.play(Ro3.class, 20);
    }
}

EnumMap分发

package onJava.enums.multi;

import java.util.EnumMap;
import onJava.enums.multi.Enums.*;

import static onJava.enums.multi.Outcome.*;

public enum Ro5 implements Competitor<Ro5> {

    PAPER, SCISSORS, ROCK;

    static EnumMap<Ro5, EnumMap<Ro5, Outcome>> table = new EnumMap<Ro5, EnumMap<Ro5, Outcome>>(Ro5.class);

    static {
        for (Ro5 it : Ro5.values()) {
            table.put(it, new EnumMap<Ro5, Outcome>(Ro5.class));
        }
        //初始化好预期的类型和结果
        initRow(PAPER, DRAW, LOSE, WIN);
        initRow(SCISSORS, WIN, DRAW, LOSE);
        initRow(ROCK, LOSE, WIN, DRAW);
    }

    static void initRow(Ro5 it, Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {
        EnumMap<Ro5, Outcome> row = Ro5.table.get(it);

        row.put(Ro5.PAPER, vPAPER);
        row.put(Ro5.SCISSORS, vSCISSORS);
        row.put(Ro5.ROCK, vROCK);
    }


    @Override
    public Outcome compete(Ro5 it) {
        return table.get(this).get(it);
    }

    public static void main(String[] args) {
        Ro.play(Ro5.class, 20);
    }
}

二位数组分发(最简洁方案)

package onJava.enums.multi;
import static onJava.enums.multi.Outcome.*;

public enum Ro6 implements Competitor<Ro6> {
    PAPER, SCISSORS, ROCK;

    //布、剪刀、石头
    private static Outcome[][] table = {
            {DRAW, LOSE, WIN},
            {WIN, DRAW, LOSE},
            {LOSE, WIN, DRAW}
    };

    /**
     *      布       剪刀     石头
     * 布    DRAW    LOSE    WIN
     * 剪刀   WIN     DRAW    LOSE
     * 石头   LOSE    WIN     DRAW
     * 
     */


    @Override
    public Outcome compete(Ro6 other) {
        return table[this.ordinal()][other.ordinal()];
    }

    public static void main(String[] args) {
        Ro.play(Ro6.class, 20);
    }
}

以上就是5种“多路分发”的实现方式,关注我,给你看更多精彩分享

分类:

后端

标签:

后端

作者介绍

疾风步行者
V1

还在奔跑的老程序员