关于访客模式的问题(Java中的示例)

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树)

Jef*_*ter 5

访客模式只是双重调度.

我不确定我是否同意您对访问者的实施.我会实现这样的事情:

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"检查.它使您能够将用于处理层次结构的逻辑分离到单独的类中.它还使您能够在不更改原始类的情况下添加新行为.


Nic*_*uet 4

访问者模式是一个奇特的开关案例/模式匹配系统,以促进图形遍历

由于典型的函数式语言提供模式匹配和遍历图形的有效方法,因此兴趣更加有限。

即使在 JAVA 中,使用instanceof或使用enum,访问者也更像是一种奇特的执行方式,而不是通用解决方案,因为许多算法不能很好地适应它。