Seb*_*ber 6 java design-patterns visitor
我只是想了解使用访问者模式的主要好处.
这是一个Java实现示例
///////////////////////////////////
// Interfaces
interface MamalVisitor {
void visit(Mammal mammal);
}
interface MammalVisitable {
public void accept(MamalVisitor visitor);
}
interface Mammal extends MammalVisitable {
public int getLegsNumber();
}
///////////////////////////////////
///////////////////////////////////
// Model
class Human implements Mammal {
@Override
public void accept(MamalVisitor visitor) { visitor.visit(this); }
@Override
public int getLegsNumber() { return 2; }
}
//PIRATE HAS A WOOD LEG
class Pirate extends Human {
@Override
public int getLegsNumber() { return 1; }
public int getWoodLegNumber() { return 1; }
}
class Dog implements Mammal {
@Override
public void accept(MamalVisitor visitor) { visitor.visit(this); }
@Override
public int getLegsNumber() { return 4; }
}
///////////////////////////////////
///////////////////////////////////
class LegCounterVisitor implements MamalVisitor {
private int legNumber = 0;
@Override
public void visit(Mammal mammal) { legNumber += mammal.getLegsNumber(); }
public int getLegNumber() { return legNumber; }
}
class WoodLegCounterVisitor implements MamalVisitor {
private int woodLegNumber = 0;
@Override
public void visit(Mammal mammal) {
// perhaps bad but i'm lazy
if ( mammal instanceof Pirate ) {
woodLegNumber += ((Pirate) mammal).getWoodLegNumber();
}
}
public int getWoodLegNumber() { return woodLegNumber; }
}
///////////////////////////////////
///////////////////////////////////
public class Main {
public static void main(String[] args) {
// Create a list with 9 mammal legs and 3 pirate woodlegs
List<Mammal> mammalList = Arrays.asList(
new Pirate(),
new Dog(),
new Human(),
new Pirate(),
new Pirate()
);
///////////////////////////////////
// The visitor method
LegCounterVisitor legCounterVisitor = new LegCounterVisitor();
WoodLegCounterVisitor woodLegCounterVisitor = new WoodLegCounterVisitor();
for ( Mammal mammal : mammalList ) {
mammal.accept(legCounterVisitor);
mammal.accept(woodLegCounterVisitor);
// why not also using:
// legCounterVisitor.visit(mammal);
// woodLegCounterVisitor.visit(mammal);
}
System.out.println("Number of legs:" + legCounterVisitor.getLegNumber());
System.out.println("Number of wood legs:" + woodLegCounterVisitor.getWoodLegNumber());
///////////////////////////////////
// The standart method
int legNumber = 0;
int woodLegNumber = 0;
for ( Mammal mammal : mammalList ) {
legNumber += mammal.getLegsNumber();
// perhaps bad but i'm lazy
if ( mammal instanceof Pirate ) {
woodLegNumber += ((Pirate) mammal).getWoodLegNumber();
}
}
System.out.println("Number of legs:" + legNumber);
System.out.println("Number of wood legs:" + woodLegNumber);
}
}
///////////////////////////////////
Run Code Online (Sandbox Code Playgroud)
我只是想知道这种情况下使用这种模式的主要优点是什么.我们也可以遍历集合并获得几乎相同的东西,除了我们不必处理新的接口并向模型添加样板代码...
使用Apache Commons或功能语言,经典的方式似乎是做一些map/reduce操作(映射到腿数并减少添加),这很容易......
我也想知道为什么要用它们
mammal.accept(legCounterVisitor);
mammal.accept(woodLegCounterVisitor);
Run Code Online (Sandbox Code Playgroud)
并不是
legCounterVisitor.visit(mammal);
woodLegCounterVisitor.visit(mammal);
Run Code Online (Sandbox Code Playgroud)
第二个选项似乎删除了模型部件上的accept(...)方法.
在我发现的许多样本中,似乎它们没有为模型对象使用通用接口.我添加它是因为我只需要添加一个访问(哺乳动物)方法,而不是为每个哺乳动物实现一个.让我的所有对象实现哺乳动物是好的吗?(我猜有时它无论如何都不可能).它仍然是这样的访客模式吗?
所以我的问题是: - 你看到我使用访客的例子有什么优势吗? - 如果没有,你能为游客提供一些具体的用例吗? - 访问者在函数式编程语言中很有用
我发现与此模式相关的唯一例子是漂亮的打印机,在访问者的状态中保持在访问不同节点期间使用的偏移量(例如,用于显示XML树)
访客模式只是双重调度.
我不确定我是否同意您对访问者的实施.我会实现这样的事情:
interface MammalVisitor {
void visit(Pirate pirate);
void visit(Human human);
void visit(Dog dog);
}
// Basic visitor provides no-op behaviour for everything.
abstract class MammalAdapter implements MammalVisitor {
void visit(Pirate pirate) {};
void visit(Human human) {};
void visit(Dog dog) {};
}
Run Code Online (Sandbox Code Playgroud)
然后实施将变得更加清洁:
// We only want to provide specific behaviour for pirates
class WoodLegCounterVisitor extends MammalAdaptor {
private int woodLegNumber = 0;
@Override
public void visit(Pirate pirate) {
woodLegNumber += pirate.getWoodLegNumber();
}
public int getWoodLegNumber() { return woodLegNumber; }
}
Run Code Online (Sandbox Code Playgroud)
在回答您的实际问题时,使用访问者的主要优点是无需进行"instanceof"检查.它使您能够将用于处理层次结构的逻辑分离到单独的类中.它还使您能够在不更改原始类的情况下添加新行为.