Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >双重调度和继承

双重调度和继承
EN

Stack Overflow用户
提问于 2016-01-02 21:41:16
回答 1查看 214关注 0票数 3

我有许多哑巴对象类,我想将它们序列化为String,用于进程外存储。这是一个非常典型的使用双重调度/访问者模式的地方。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Serializeable {
  <T> T serialize(Serializer<T> serializer);
}

public interface Serializer<T> {
  T serialize(Serializeable s);
  T serialize(FileSystemIdentifier fsid);
  T serialize(ExtFileSystemIdentifier extFsid);
  T serialize(NtfsFileSystemIdentifier ntfsFsid);
}

public class JsonSerializer implements Serializer<String> {
  public String serialize(Serializeable s) {...}
  public String serialize(FileSystemIdentifier fsid) {...}
  public String serialize(ExtFileSystemIdentifer extFsid) {...}
  public String serialize(NtfsFileSystemIdentifier ntfsFsid) {...}
}

public abstract class FileSystemIdentifier implements Serializeable {}
public class ExtFileSystemIdentifier extends FileSystemIdentifier {...}
public class NtfsFileSystemIdentifier extends FileSystemIdentifier {...}

使用此模型,保存数据的类不需要知道序列化该数据的可能方法。例如,JSON是一种选择,但是另一个序列化程序可能会将数据类“序列化”成SQL insert语句。

如果我们看一下其中一个数据类的实现,实现看起来与所有其他类几乎相同。该类在传递给它的Serializer上调用serialize()方法,并将其自身作为参数提供。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ExtFileSystemIdentifier extends FileSystemIdentifier {
  public <T> T serialize(Serializer<T> serializer) {
    return serializer.serialize(this);
  }
}

我理解为什么这个通用代码不能被拉到父类中。尽管代码是共享的,但编译器清楚地知道何时在该方法中this的类型是ExtFileSystemIdentifier,并且可以(在编译时)写出字节码来调用serialize()的最特定于类型的重载。

当涉及到V表查找时,我相信我也理解大部分发生的事情。编译器只知道抽象类型为Serializerserializer参数。它必须在运行时查看serializer对象的V表,以发现特定子类的serialize()方法的位置,在本例中为JsonSerializer.serialize()

典型的用法是获取一个称为Serializable的数据对象,并通过将其提供给一个称为Serializer的串行化程序对象来序列化它。对象的特定类型在编译时是未知的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<Serializeable> list = //....
Serializer<String> serializer = //....

list.stream().map(serializer::serialize)

此实例的工作方式类似于其他调用,但与之相反。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class JsonSerializer implements Serializer<String> {
  public String serialize(Serializeable s) {
    s.serialize(this);
  }
  // ...
}  

现在,在Serializable的实例上完成了V表查找,例如,它将找到ExtFileSystemIdentifier.serialize。它可以静态地确定最接近的匹配重载是用于Serializer<T>的(它恰好也是唯一的重载)。

这一切都很好。它实现了使输入和输出数据类不受序列化类影响的主要目标。而且,它还实现了第二个目标,即为序列化类的用户提供一致的API,而不管正在执行哪种类型的序列化。

现在想象一下,第二组哑巴数据类存在于不同的项目中。需要为这些对象编写一个新的序列化程序。现有的Serializable接口可以在这个新项目中使用。但是,Serializer接口包含对来自另一个项目的数据类的引用。

为了推广这一点,可以将Serializer接口分成三部分

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Serializer<T> {
  T serialize(Serializable s);
}

public interface ProjectASerializer<T> extends Serializer<T> {
  T serialize(FileSystemIdentifier fsid);
  T serialize(ExtFileSystemIdentifier fsid);
  // ... other data classes from Project A
}

public interface ProjectBSerializer<T> extends Serializer<T> {
  T serialize(ComputingDevice device);
  T serialize(PortableComputingDevice portable);
  // ... other data classes from Project B
}

通过这种方式,可以对SerializerSerializable接口进行打包和重用。然而,这打破了双重分派,并导致代码中的无限循环。这是我在V表查找中不确定的部分。

在调试器中单步执行代码时,在数据类的serialize方法中出现问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ExtFileSystemIdentifier implements Serializable {
  public <T> T serialize(Serializer<T> serializer) {
    return serializer.serialize(this);
  }
}

我认为发生的情况是在编译时,编译器试图从Serializer接口的可用选项中为serialize方法选择正确的重载(因为编译器只知道它是一个Serializer<T>)。这意味着当我们到达运行时执行V表查找时,正在查找的方法是错误的方法,运行时将选择JsonSerializer.serialize(Serializable),从而导致无限循环。

此问题的一种可能的解决方案是在数据类中提供更加特定于类型的serialize方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface ProjectASerializable extends Serializable {
  <T> T serialize(ProjectASerializer<T> serializer);
}

public class ExtFileSystemIdentifier implements ProjectASerializable {
  public <T> T serialize(Serializer<T> serializer) {
    return serializer.serialize(this);
  }
  public <T> T serialize(ProjectASerializer<T> serializer) {
    return serializer.serialize(this);
  }
}

程序控制流将不断跳跃,直到达到最特定类型的Serializer重载。此时,对于来自项目A的数据类,ProjectASerializer<T>接口将具有更具体的serialize方法;从而避免了无限循环。

这使得双重分派的吸引力略有下降。现在数据类中有了更多的样板代码。这已经够糟糕的了,显然重复的代码不能被分解到父类中,因为它绕过了双重调度的把戏。现在,它更多了,并且它与序列化程序的继承深度相结合。

双重分派是静态类型技巧。有没有更多的静态类型技巧可以帮助我避免重复的代码?

EN

回答 1

Stack Overflow用户

发布于 2016-02-10 12:52:01

正如您所注意到的,serialize方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Serializer<T> {
  T serialize(Serializable s);
}

没有任何意义。访问者模式是用来进行案例分析的,但是使用这种方法没有任何进展(您已经知道它是一个Serializable),因此不可避免地要进行无限递归。

有意义的是一个至少有一个具体类型要访问的基本Serializer接口,以及在两个项目之间共享的具体类型。如果没有共享的具体类型,那么就没有希望使用Serializer层次结构。

现在,如果您希望在实现访问者模式时减少样板,我建议使用代码生成器(通过注释处理),例如。adt4jderive4j

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34571009

复制
相关文章
「R」ggplot2在R包开发中的使用
没有特别系统的学习 tidy evaluation 这方面的高级操作,最近有空准备补一补,学习下这方面的知识。
王诗翔呀
2022/03/30
6.7K0
集成光路中的光栅
所谓光栅,就是通过一定的微加工手段,使得材料的折射率满足一定的分布,从而实现对光操控的一类光器件。典型的光栅结构,示意图如下,
光学小豆芽
2020/08/14
2.3K0
对SVG动画进行异步懒光栅化处理 [每日前端夜话(0x17)]
在转换 SVG 图像时,浏览器会试着在每一帧上进行渲染,以便使图像尽可能的清晰。 不幸的是,SVG渲染可能会很慢,特别是对于较大的图像。
疯狂的技术宅
2019/03/27
1.3K0
对SVG动画进行异步懒光栅化处理 [每日前端夜话(0x17)]
光栅图形学的中的算法
——对《计算机图形学基础教程》胡事民等著 的补充
种花家的奋斗兔
2020/11/13
1.2K0
光栅图形学的中的算法
网页光栅化_光栅净化
资料:https://blog.csdn.net/luoshengyang/article/details/51348829
全栈程序员站长
2022/11/01
2440
在Exce中使用带有动态数组公式的切片器
Excel中,有一些特别的函数仅计算可见行,例如SUBTOTAL函数和AGGREGATE函数。本文示例使用SUBTOTAL函数。
fanjy
2023/08/29
5160
在Exce中使用带有动态数组公式的切片器
原 在PostgreSQL中秒级完成大表添加带有not null属性并带有default值的实验
近期同事在讨论如何在PostgreSQL中一张大表,添加一个带有not null属性的,且具有缺省值的字段,并且要求在秒级完成。 因为此,有了以下的实验记录: 首先我们是在PostgreSQL 10下做的实验: postgres=# select version(); version ---------------
王果壳
2018/05/17
8.2K0
sql中带有like时如何使用预编译。
Java代码如下: String str = "长江"; Connection conn = null; //比较preparestatement和statement PreparedStatem
geekfly
2022/05/06
9730
在zabbix中实现发送带有图片的邮件和微信告警
可以手动触发一个报警测试效果,手机上就可以收到带图的报警了,点击消息之后的页面也可以看到历史的图片
没有故事的陈师傅
2019/11/10
2.4K0
GPX数据在mapboxGL中轨迹动画
喜欢跑步的人都会选择一款APP来自己跑步的,常用的有keep、悦跑圈、华为健康等等,每次跑完步,会根据跑步的轨迹绘制轨迹动画。今天咱们讲讲技术,不扯淡,讲一下在mapboxGL中如何实现类似的效果。
牛老师讲GIS
2020/06/08
2K0
GPX数据在mapboxGL中轨迹动画
光栅化[通俗易懂]
定义一个宽高比(Aspect Ratio);还有垂直可视角度 vertical field-of-view (fovY) 。垂直可视角度即从相机原点到上顶中点和下底中点的连线的夹角,可视角度大可以类比成广角相机,它张得就比较开,适合拍近距离的物体;可视角度小,透视投影就越不明显,越像正交投影,就很容易能拍到远处的物体。水平可视角度可以类比。
全栈程序员站长
2022/09/06
1.2K0
光栅化[通俗易懂]
带有CSS3的动画3D条形图
关于如何使用CSS创建动画三维条形图的教程。 这一切都是从一个小实验开始的,这个实验受到了来自Nettuts +的教程的启发,它展示了如何使用CSS,图像和JavaScript将3D条形图嵌入到HTML页面中。在阅读完教程之后,我挑战自己将这个想法变成纯粹的CSS,看看我能做多少。最初的挑战是创造一个经典的半透明的6方框3D盒子。最后的挑战是创建一个完整的三维条形图,我们将在本教程中创建。 你可以看看我以前做过这里。 请注意:本教程的结果只能在支持相应CSS属性的浏览器中按预期方式工作。 我们写下一些关
企鹅号小编
2018/01/15
8800
带有CSS3的动画3D条形图
在vscode中配置R的开发环境
有时候各位使用R的用户不知道会不会有这样的感觉,visual studio和Rstudio由于负载过重,在打开或者加载R script时会出现加载过慢的情况,但对于很多数据工作者来说,variable inspector和data view这类的数据可视化功能必不可少,而visual studio和Rstudio在这方面做得可以说是非常完善。在这时候笔者就想到了visual studio code,毕竟作为宇宙最强IDE的减配和开源版本(这里形容可能不太准确),各种语言相应的开发插件众多。更加让笔者惊喜的是,目前vscode-R一直处于开发阶段,并且在最近的1.2.0版本结合了vscode关于web view的API,添加了R session watcher——一个集成的数据可视化构架,并且在1.21中完善了windows系统下的extension的bug。我们来看看集成的viewer会有什么样的效果:
用户7652506
2020/08/12
11.8K0
在vscode中配置R的开发环境
光栅化 (Rasterization)
上一篇文章讨论了如何在多边形的某一点上分配光强度值,这里主要讨论如何为多边形确定实际的像素,即在栅格屏幕上的对应位置,这个过程称为光栅化(Rasterization)或者扫描转换 (Scan conversion)。
全栈程序员站长
2022/09/20
6800
通过在线平面图网站设计漂亮的平面图
平面图,又称图则,是建筑物工程图的组成部分。当测区面积不大,半径小于10公里(甚至25公里)时,可以用水平面代替水准面。在这个前提下,可以把测区内的地面景物沿铅垂线方向投影到平面上,按规定的符号和比例缩小而构成相似图形,即为平面图。平面图以比例图绘制,表现该建筑物内的客厅、房间、空间及其它硬件的分布,其中包括主力墙、出入口、窗的位置图。
用户5442762
2019/06/10
12K0
使用带有MySQL Router的Replica Set
您可以使用MySQL Router 8.0.19和更高版本对replica set进行引导,就像可以引导InnoDB cluster一样,将MySQL路由器与InnoDB Cluster结合使用”。生成的MySQL路由器配置文件的唯一区别是添加了cluster_type选项。将MySQL路由器引导到副本集时,生成的配置文件包括:
卖菜小弟
2020/01/22
2K0
Python在tkinter界面中显示matplotlib动画
在tkinter应用程序界面中同时显示matplotlib绘制的动态折线图、动态散点图和动态柱状图。
Python小屋屋主
2020/02/23
5K0
点击加载更多

相似问题

平面图动画R中的图像标签

10

将坐标更改为R中具有多层的一系列光栅

11

光栅R

13

在R中输出光栅层

11

如何使用r中的光栅包在光栅中显示所有列名

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文