一、枚举类型——多路分发

news/2024/11/16 21:00:07/

当你处理多个交互类型时,程序可能会变得相当混乱。举例来说,考虑一个解析并执行数学表达式的系统。里面可能包括 Number.plus(Number)、Number.multiply(Number) 等,此处的 Number 是数值对象家族的基类。但是当你要执行 a.plus(b),并且不知道 a 或 b 的具体类型时,如何保证它们间的相互作用是正确的?

答案一开始可能让你意外:Java 只能进行单路分发。也就是说,如果你想对多个类型未知的对象进行操作,Java 只会对其中一个类型调用动态绑定机制。这并不能解决当前
的问题,所以你最终只能手动检测类型,然后再实现你自己的动态绑定行为。

这个问题的解决方法就是多路分发(此处称为双路分发,因为只有两路)。多态只能在方法调用时发生,所以如果你要使用双路分发,就必须执行两次方法调用:第一次用来确定第一个未知类型,第二次用来确定第二个未知类型。要使用多路分发,就必须对每个类型都进行虚拟调用——如果是在操作两个不同的交互类型层次结构,则需要在每个层次结构都执行虚拟调用。这通常会启用一个配置,使得一次方法调用可以产生多次虚拟调用,从而服务于过程中的多个类型。

要达到这个目的,你需要不止一个方法互相配合:每个分发都需要一个方法调用。以下示例(实现了一个“猜拳”游戏)中对应的方法是 compete() 和 eval(),它们都是相同类型的成员,会生成三个可能结果中的一个:

Outcome.java

public enum Outcome {WIN, LOSE, DRAW}

Item是多路分发类型的接口:

Item.java

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

每个特定的Item都提供了这些方法的对应实现:

Paper.java

import static enums.TEST0005.Outcome.*;public class Paper implements Item {@Overridepublic Outcome compete(Item it) {return it.eval(this);}@Overridepublic Outcome eval(Paper p) {return DRAW;}@Overridepublic Outcome eval(Scissors s) {return WIN;}@Overridepublic Outcome eval(Rock r) {return LOSE;}@Overridepublic String toString() {return "Paper";}
}

Scissors.java

import static enums.TEST0005.Outcome.*;public class Scissors implements Item {@Overridepublic Outcome compete(Item it) {return it.eval(this);}@Overridepublic Outcome eval(Paper p) {return LOSE;}@Overridepublic Outcome eval(Scissors s) {return DRAW;}@Overridepublic Outcome eval(Rock r) {return WIN;}@Overridepublic String toString() {return "Scissors";}
}

Rock.java

import static enums.TEST0005.Outcome.*;public class Rock implements Item {@Overridepublic Outcome compete(Item it) {return it.eval(this);}@Overridepublic Outcome eval(Paper p) {return WIN;}@Overridepublic Outcome eval(Scissors s) {return LOSE;}@Overridepublic Outcome eval(Rock r) {return DRAW;}@Overridepublic String toString() {return "Rock";}
}

RoShamBo1.match() 接收两个 Item 对象作为参数,然后通过调用 Item.compete() 幵始执行双路分发:

RoShamBo1.java

import java.util.Random;public class RoShamBo1 {static final int SIZE = 20;private static Random rand = new Random(47);public static Item newItem() {switch (rand.nextInt(3)) {default:case 0:return new Scissors();case 1:return new Paper();case 2:return new Rock();}}public static void match(Item a, Item b) {System.out.println(a + " vs. " + b + ": " + a.compete(b));}public static void main(String[] args) {for (int i = 0; i < SIZE; i++) {match(newItem(), newItem());}}
}

虚拟机制决定了 a 的类型,因此它在 a 的实际类型的 compete() 函数中唤醒。compete() 函数通过对剩余类型调用 eval() 方法,调用执行了第二次分发。将自身 (this) 作为参数传入 eval(),会产生一个对重载 eval() 的调用,由此保留了第一次分发的类型信息。当第二次分发结束后,你就知道了两个 Item 对象的准确类型。

构建多路分发需要很多道工序,但是记住它所带来的好处:在调用中保持了语法的优雅,而不是在调用中编写丑陋的代码来确定一个又一个的对象类型。你只需要说:“你们两个!我不关心你们是什么类型,你们自己处理好彼此的交互!”当然,在决定使用多路分发前,要确定这种优雅的语法确实对你很重要。


http://www.ppmy.cn/news/572583.html

相关文章

基于51单片机设计的计算器

一、项目介绍 计算器是一种常见的电子产品,广泛应用于各个领域。而基于单片机的计算器设计则是学习单片机的一个重要环节。本项目基于STC89C52单片机设计了一款基本的四则运算计算器。 项目里采用了单片机的IO口、定时器和LCD1602显示屏等技术原理。其中,IO口用于控制矩阵键…

Jetpack Compose 入门难点解疑

作者&#xff1a;晴天小庭 近些年声明式布局开发方式逐渐从网页端延展到了手机端&#xff0c;说到底还是声明式太香了&#xff0c;其代码更加清晰、简洁&#xff0c;并且更接近于自然语言的表达方式。这使得代码易于理解和维护&#xff0c;降低了开发人员的心智负担。 谷歌和苹…

Ubuntu下使用迅雷看看

从网上找的方法&#xff0c;已经通过本人的验证&#xff0c;可用。 1. 使用firefox浏览器&#xff0c;可以直接使用User Agent Switcher选择iphone即可&#xff0c;没有这个插件&#xff0c;就下载一个&#xff0c;很容易的。 2. 使用chrome, 可以在没一个打开的迅雷看看上的…

优化迅雷看看片库

网络视频一直是我们的最爱&#xff0c;搜索→下载→播放也成了一条大家熟知的网络视频“三步曲”。迅雷狗狗为我们提供了良好的搜索功能&#xff0c;迅雷提供了高速、安全的下载&#xff0c;而迅雷影音播放器则提供了更好的播放体验。近日迅雷影音2.3.0.172版也已经发布正式版&…

阻止迅雷播放器暂停广告

CtrlR 打开cmd输入 wf.msc 添加两个出站规则 步骤-禁止迅雷播放器联网 步骤同上-禁止迅雷下载引擎(程序路径修改为下载引擎路径就可以了) 程序目录参考 D:\software\生活工具\迅雷播放器\Xmp\Program\Xmp.exe D:\software\生活工具\迅雷播放器\Xmp\Program\resources\bin\SDK…

迅雷看看与RealMedia codec

在新笔记本上安装klcodec453f.exe&#xff0c;包括了Media Player Classic&#xff0c;发现无法播放rvmb文件。感觉很奇怪&#xff0c;因为刚刚在一台VISTA上安装klcodec453f.exe后&#xff0c;直接就可以播放rvmb文件。 于是到VISTA上启动gspot.exe&#xff0c;列出所有的code…

HEVC播放器出炉,迅雷看看支持H.265

http://tieba.baidu.com/p/2243767049 感谢D大。 新版本迅雷看看开始支持HEVC解码&#xff0c;http://tech.sina.com.cn/i/2013-03-30/19148197086.shtml 对解码测试一遍进行一边做个报告. 首先安装解码器, 因为是dshow的组件, 安装是很容易的, 在PotPlayer上也很容易加载, …

迅雷看看网站设计分析

很久之前就想写篇关于迅雷网站的设计分析文章了&#xff0c;迅雷看看一直是我在线看电影的网站&#xff0c;也是我比较喜欢的网站&#xff0c;所以我也比较乐于分析一下它的设计&#xff0c;先从结构上分析&#xff0c;也就是导航、搜索、详细信息展示、以及播放页面的顺序。 …