什么是多路分发和实现
【摘要】 比如要执行一个通用的数学计算,计算表达式可能是a.plus(b),但是不知道a和b的具体类型,如果按照普通的做法,需要对a和b做两次类型判断,这种写法不够优雅。
什么是多路分发
比如要执行一个通用的数学计算,计算表达式可能是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 0: return new Scissors();
case 1: return new Paper();
case 2: return 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>> T random(Class<T> ec) {
return random(ec.getEnumConstants());
}
public static <T> 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;
default: return null;
}
}
},
SCISSORS {
@Override
public Outcome compete(Ro3 it) {
switch (it) {
case PAPER: return WIN;
case SCISSORS: return DRAW;
case ROCK: return LOSE;
default: return null;
}
}
},
ROCK {
@Override
public Outcome compete(Ro3 it) {
switch (it) {
case PAPER: return LOSE;
case SCISSORS: return WIN;
case ROCK: return DRAW;
default: return 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种“多路分发”的实现方式,关注我,给你看更多精彩分享
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)