【发布时间】:2021-06-03 04:54:39
【问题描述】:
所以,我只是在阅读访问者模式,发现访问者和元素之间的来回很奇怪!
基本上我们称之为元素,我们将访问者传递给它,然后元素将自身传递给访问者。然后访问者操作元素。什么?为什么?感觉太没必要了。我称之为“来回疯狂”。
因此,当需要在所有元素上执行相同的操作时,访问者的目的是将元素与其操作分离。这是为了防止我们需要用新的动作来扩展我们的元素,我们不想进入所有这些类并修改已经稳定的代码。所以我们在这里遵循 Open/Closed 原则。
为什么会有这么多来回,如果我们没有这些,我们会失去什么?
例如,我编写的这段代码牢记了这一目的,但跳过了访问者模式的疯狂交互。基本上我有会跳和吃的动物。我想将这些动作与对象分离,因此我将这些动作移至访客。进食和跳跃会增加动物的健康(我知道,这是一个非常愚蠢的例子……)
public interface AnimalAction { // Abstract Visitor
public void visit(Dog dog);
public void visit(Cat cat);
}
public class EatVisitor implements AnimalAction { // ConcreteVisitor
@Override
public void visit(Dog dog) {
// Eating increases the dog health by 100
dog.increaseHealth(100);
}
@Override
public void visit(Cat cat) {
// Eating increases the cat health by 50
cat.increaseHealth(50);
}
}
public class JumpVisitor implements AnimalAction { // ConcreteVisitor
public void visit(Dog dog) {
// Jumping increases the dog health by 10
dog.increaseHealth(10);
}
public void visit(Cat cat) {
// Jumping increases the cat health by 20
cat.increaseHealth(20);
}
}
public class Cat { // ConcreteElement
private int health;
public Cat() {
this.health = 50;
}
public void increaseHealth(int healthIncrement) {
this.health += healthIncrement;
}
public int getHealth() {
return health;
}
}
public class Dog { // ConcreteElement
private int health;
public Dog() {
this.health = 10;
}
public void increaseHealth(int healthIncrement) {
this.health += healthIncrement;
}
public int getHealth() {
return health;
}
}
public class Main {
public static void main(String[] args) {
AnimalAction jumpAction = new JumpVisitor();
AnimalAction eatAction = new EatVisitor();
Dog dog = new Dog();
Cat cat = new Cat();
jumpAction.visit(dog); // NOTE HERE. NOT DOING THE BACK AND FORTH MADNESS.
eatAction.visit(dog);
System.out.println(dog.getHealth());
jumpAction.visit(cat);
eatAction.visit(cat);
System.out.println(cat.getHealth());
}
}
【问题讨论】:
-
恕我直言,在与访问者进行推理时,我通常使用树形模式,其中您有不同类型的
Nodes(例如,考虑一些节点代表运算符的 AST,而其他操作数等则代表 @987654325 @ 例如Equals(Plus(Literal(1), Literal(1)), Literal(2))显然Equals/Plus等是通用的,因为表达式不需要是简单的文字,现在想想你将如何编写一个评估这个表达式的访问者......然后写一些代码解析表达式的文本并对其进行评估,现在您在编译时有 0 个已知的具体类 -
@GACy20 你是对的。这段代码有效的唯一原因是因为我已经知道狗是狗,猫是猫。感谢这个例子,它给访问者更多的意义。
-
使用
dog的代码和使用cat的代码看起来相同,所以如果您尝试将它们放入列表并使用会发生什么一个循环? -
我认为 Shvets 很好地合理化了访问者模式;当您需要 扩展现有类 以实现一些常见行为时,您可以使用它 - 因此您需要使用“双重调度” - sourcemaking.com/design_patterns/visitor 当您不需要时有这个约束要处理,通常有更简单的方法来实现相同的目标。
-
另见我的回答here,它可能会给你带来一些进一步的见解。
标签: java design-patterns visitor-pattern