- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有很多关于将算法与类解耦的讨论。但是,有一件事没有解释。
他们像这样使用访问者
abstract class Expr {
public <T> T accept(Visitor<T> visitor) { return visitor.visit(this); }
}
class ExprVisitor extends Visitor{
public Integer visit(Num num) {
return num.value;
}
public Integer visit(Sum sum) {
return sum.getLeft().accept(this) + sum.getRight().accept(this);
}
public Integer visit(Prod prod) {
return prod.getLeft().accept(this) * prod.getRight().accept(this);
}
Visitor 不是直接调用visit(element),而是要求元素调用它的visit 方法。它与类(Class)不了解访客的公开想法相矛盾。
getLeft()
返回基本
Expression
, 拨打
visit(getLeft())
将导致
visit(Expression)
, 而
getLeft()
调用
visit(this)
将导致另一个更合适的访问调用。所以,
accept()
执行类型转换(又名强制转换)。
accept()
方法是不必要的;为该技术引入术语‘Walkabout’。”
最佳答案
访客模式的visit
/accept
由于类 C 语言(C#、Java 等)的语义,构造是必要的邪恶。访问者模式的目标是使用双重调度来路由您的调用,正如您在阅读代码时所期望的那样。
通常,当使用访问者模式时,会涉及一个对象层次结构,其中所有节点都来自基础 Node
。类型,以下简称 Node
.本能地,我们会这样写:
Node root = GetTreeRoot();
new MyVisitor().visit(root);
MyVisitor
类定义如下:
class MyVisitor implements IVisitor {
void visit(CarNode node);
void visit(TrainNode node);
void visit(PlaneNode node);
void visit(Node node);
}
root
的实际类型如何也就是说,我们的调用将进入重载
visit(Node node)
.这对于声明为
Node
类型的所有变量都是正确的。 .这是为什么?因为 Java 和其他类似 C 的语言在决定调用哪个重载时只考虑参数的静态类型或声明变量的类型。 Java 没有采取额外的步骤来询问,对于每个方法调用,在运行时,“好吧,
root
的动态类型是什么?哦,我明白了。它是一个
TrainNode
。让我们看看其中是否有任何方法
MyVisitor
接受类型为
TrainNode
...”的参数。编译器在编译时确定要调用的方法。 (如果 Java 确实检查了参数的动态类型,性能会非常糟糕。)
MyVisitor
,通过虚方法),还要考虑参数的类型(我们在看什么类型的
Node
)?访问者模式允许我们通过
visit
来做到这一点。/
accept
组合。
root.accept(new MyVisitor());
TrainElement
,我们将输入
TrainElement
的实现
accept()
:
class TrainNode extends Node implements IVisitable {
void accept(IVisitor v) {
v.visit(this);
}
}
TrainNode
的范围内的
accept
?
它知道 this
的静态类型是 TrainNode
.这是编译器在我们的调用者范围内不知道的重要附加信息:在那里,它知道关于
root
的所有信息。是它是
Node
.现在编译器知道
this
(
root
) 不仅仅是
Node
,但它实际上是一个
TrainNode
.结果,在
accept()
中找到了一行:
v.visit(this)
, 完全意味着别的东西。编译器现在将查找
visit()
的重载这需要一个
TrainNode
.如果找不到,它就会将调用编译为一个重载,该重载带有
Node
.如果两者都不存在,你会得到一个编译错误(除非你有一个需要
object
的重载)。因此,执行将进入我们一直以来的意图:
MyVisitor
的实现
visit(TrainNode e)
.不需要类型转换,最重要的是,不需要反射(reflection)。因此,这种机制的开销相当低:它只包含指针引用而没有其他内容。
abstract class Node { ... }
abstract class BinaryNode extends Node { Node left, right; }
abstract class AdditionNode extends BinaryNode { }
abstract class MultiplicationNode extends BinaryNode { }
abstract class LiteralNode { int value; }
class Interpreter implements IVisitor<int> {
int visit(AdditionNode n) {
int left = n.left.accept(this);
int right = n.right.accept(this);
return left + right;
}
int visit(MultiplicationNode n) {
int left = n.left.accept(this);
int right = n.right.accept(this);
return left * right;
}
int visit(LiteralNode n) {
return n.value;
}
}
left
的类型或
right
在
visit()
方法。我们的解析器很可能也只返回一个
Node
类型的对象。它也指向层次结构的根,所以我们也不能安全地进行转换。所以我们的简单解释器看起来像:
Node program = parse(args[0]);
int result = program.accept(new Interpreter());
System.out.println("Output: " + result);
visit()
该新类型的方法进入
IVisitor
界面,并在我们所有的访问者中创建 stub (或完整)实现。我们还需要添加
accept()
方法也是如此,原因如上所述。如果性能对您来说意义不大,那么有一些解决方案可以在不需要
accept()
的情况下编写访问者。 ,但它们通常涉及反射,因此会产生相当大的开销。
关于design-patterns - 访问者模式中的 accept() 方法有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9132178/
我正在用power designer创建一个物理模型,我想将默认值添加到我的Mysql表中。 有可能吗,有人加了默认值 ? 谢谢 最佳答案 有可能,我发现“列属性”并不容易 方法如下: 选择表格(单击
关闭。这个问题是 opinion-based 。它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文来回答。 2年前关闭。 Improve t
我正在编写一个采用 Material Design 布局的应用程序,但找不到任何关于如何将对话框动画显示到屏幕上的指南。 这表明盒子应该只是“砰”的一声存在,但这似乎违背了设计的精神,包括动画和触觉。
我做了一个巨大的掠夺,不小心丢失了我的*.cs(设计文件)..我刚刚得到了*.designer文件。 我能否反过来,仅使用 .designer 文件以某种方式创 build 计文件 (*.cs),还是
如果 Google 的关键字规划器向我显示关键字“Web Design [city-name]”获得约 880 次搜索,而“Website Design [city-name]”获得约 620 次搜索
首先,代码: $(document).ready(function() { $('#member_pattern').hide(); $('.add-member').click(function()
大型软件公司之一问了这个问题。我想出了一个简单的解决方案,我想知道其他人对该解决方案有何看法。 You are supposed to design an API and a backend for
在最新的 Material Design 文档 (https://www.google.com/design/spec/what-is-material/elevation-shadows.html#
背景 我正在对从我们的 RDBMS 数据库到 MongoDB 的转换进行原型(prototype)设计。在进行非规范化时,似乎我有两种选择,一种会导致许多(数百万)个小文档,另一种会导致更少(数十万)
Qt Designer (5.11.2) 在选择 QWebEngineView-Widget 时崩溃。 我正在创建一个对话框,以将其作为 .ui 文件包含在 QGIS 3 中。在表单中,我想使用 QW
我直接从 getmdl.io(组件页面)和所有设备(多台 PC、浏览器、手机等)复制代码,汉堡菜单不在标题中居中。我似乎无法隔离 css 中的菜单图标来重新对齐它。 getmdl.io 上的所有组件代
如何为 SPA 动态初始化 materialize design lite (google) 的组件?当我在 View 中动态初始化组件时,JS 没有初始化。正如我已经尝试过使用 componentH
我正在使用 Angular 4 构建一个 Web 应用程序。对于设计,我使用的是 Material Design lite。但是,我想使用 MDL 实现一个交互式轮播,它给我流畅的外观和感觉,并且与我
它看起来像 Polymer Starter Kit包含比 Material Design Lite 更多的组件,并且现在可用。由于两者都是符合 Material Design 理念的 Google 项
我在设置 mdl-textfield 样式时遇到了一些困难。 具体来说,设置 float 标签的大小和颜色,以及按下输入字段后动画的高度和颜色。 实际上,这是我从组件列表中获取的起点。 https:/
所以,好友列表的现代概念: 假设我们有一个名为 Person 的表。现在,那个 Person 需要有很多伙伴(其中每个伙伴也在 person 类中)。构建关系的最明显方法是通过连接表。即 buddyI
如何在导航中创建子菜单项? Link Link Link Link 我不能用 用它。什么是正确的类? 最佳答案 MDL 似乎还没有原生支持子菜单。 然而
我想知道我应该遵循哪些步骤来解决设计自动售货机等问题并提出许多设计文档(如用例、序列图、类图)。是否有任何我可以阅读的来源/链接,其中讨论了如何逐步进行。 谢谢。 最佳答案 我不确定是否有任何普遍接受
早在 10 月份,Kristopher Johnson 就询问了 Accounting Software Design Patterns 他收到了几个答案,但基本上都是一样的,都指向Martin Fo
我一直在为我们的产品开发一些组件,其中之一是基于流布局面板。 我想做的是为它提供一个自定义设计器,但不会丢失其默认设计器 (System.Windows.Forms.Design.FlowLayout
我是一名优秀的程序员,十分优秀!