《On Java》-多路分发の实现

简介: 《On Java》读书笔记

什么是多路分发

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

好的解决办法就是使用多路分发,一共5种方式:

  • 方法重载分发
  • 枚举分发
  • 常量特定方法分发
  • EnumMap分发
  • 二位数组分发

下面看一个“石头剪子布”的示例。

方法重载分发

这种就是根据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种“多路分发”的实现方式,关注我,给你看更多精彩分享

相关文章
|
4月前
|
C++ Rust NoSQL
Rust 数据类型 之 类C枚举 c-like enum
Rust 数据类型 之 类C枚举 c-like enum
34 0
Rust 数据类型 之 类C枚举 c-like enum
|
Java
Java 实现汉字按照首字母分组排序
Java 实现汉字按照首字母分组排序
571 0
|
11月前
|
设计模式 Java 数据库连接
Java责任链模式:优雅解耦系统处理流程,实现高效灵活的请求处理与分发(下)
Java责任链模式:优雅解耦系统处理流程,实现高效灵活的请求处理与分发
197 0
|
11月前
|
存储 设计模式 Java
Java责任链模式:优雅解耦系统处理流程,实现高效灵活的请求处理与分发(上)
Java责任链模式:优雅解耦系统处理流程,实现高效灵活的请求处理与分发
130 0
|
算法 Java
LeetCode 455.分发饼干(Java语言)
LeetCode 455.分发饼干(Java语言)
123 0
LeetCode 455.分发饼干(Java语言)
|
分布式计算 Java Hadoop
Java实现单词计数MapReduce
本文分享实现单词计数MapReduce的方法
302 0
|
Java 数据安全/隐私保护
JAVA 实现上传图片添加水印(详细版)(上)
JAVA 实现上传图片添加水印(详细版)
960 0
JAVA 实现上传图片添加水印(详细版)(上)
|
存储 Java
Java实现图书管理系统
本篇文章是对目前Java专栏已有内容的一个总结练习,希望各位小主们在学习完面向对象的知识后,可以阅览本篇文章后,自己也动手实现一个这样的demo来加深总结应用已经学到知识并进行巩固。
376 0
Java实现图书管理系统
|
Java Windows Spring
java实现spring boot项目启动时,重启Windows进程
java实现spring boot项目启动时,重启Windows进程
476 0
|
数据可视化 Java
Java实现拼图小游戏(1)—— JFrame的认识及界面搭建
如果要在某一个界面里面添加功能的话,都在一个类中,会显得代码难以阅读,而且修改起来也会很困难,所以我们将游戏主界面、登录界面、以及注册界面都单独编成一个类,每一个类都继承JFrame父类,并且在类中创建方法来来实现页面
462 0
Java实现拼图小游戏(1)—— JFrame的认识及界面搭建