关于访问者模式的问题(Java示例)
我只是想了解使用访问者模式的主要好处 下面是一个示例Java实现关于访问者模式的问题(Java示例),java,design-patterns,visitor,Java,Design Patterns,Visitor,我只是想了解使用访问者模式的主要好处 下面是一个示例Java实现 /////////////////////////////////// // Interfaces interface MamalVisitor { void visit(Mammal mammal); } interface MammalVisitable { public void accept(MamalVisitor visitor); } interface Mammal extends MammalVi
///////////////////////////////////
// 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);
}
}
///////////////////////////////////
而不是
legCounterVisitor.visit(mammal);
woodLegCounterVisitor.visit(mammal);
第二个选项似乎删除了模型零件上的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) {};
}
然后,实施将变得更为干净:
// 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; }
}
在回答您的实际问题时,使用访问者的主要优点是避免进行“instanceof”检查。它使您能够将处理层次结构的逻辑分离到单独的类中。它还使您能够在不更改原始类的情况下添加新行为。的目的是将对象结构(在您的情况下是哺乳动物)与算法(在您的情况下是计数器腿计数器算法)分离
整个想法是,您的对象(主要是java、JavaBeans)根本不会改变其结构,只会引入一个新的算法来引入一个新的算法
与的实现不同,可以使用泛型使代码更容易。这为您的访客带来了特殊性,例如:
public interface MammalVisitor<T extends Mammal> {
public void visit(T mammal);
}
public class LegCounterVisitor implements MamalVisitor<Human> {
private int legNumber = 0;
@Override
public void visit(Human mammal) { legNumber += mammal.getLegsNumber(); }
public int getLegNumber() { return legNumber; }
}
public class WoodLegCounterVisitor implements MamalVisitor<Pirate> {
private int legNumber = 0;
@Override
public void visit(Pirate mammal) {legNumber += mammal.getWoodLegNumber(); }
public int getLegNumber() { return legNumber; }
}
公共界面{
公众访问(T哺乳动物);
}
公共类LegCounterVisitor实现MamalVisitor{
私有整数=0;
@凌驾
公共无效访问(人类哺乳动物){legNumber+=哺乳动物.getLegsNumber();}
public int getLegNumber(){return legNumber;}
}
公共类WoodLegCounterVisitor实现MamalVisitor{
私有整数=0;
@凌驾
公共无效访问(海盗哺乳动物){legNumber+=emopal.getWoodLegNumber();}
public int getLegNumber(){return legNumber;}
}
是一款别致的开关盒/模式匹配系统,便于安装
由于典型的函数式语言提供了模式匹配和遍历图的有效方法,人们的兴趣受到了很大的限制
即使是在JAVA中,使用
instanceof
或使用enum
,访问者也比通用解决方案更适合执行任务,因为许多算法都不适合它。实际上,我在这里也觉得差不多。我使用了instanceof,但我想在真正复杂的访问者模式中,我们宁愿避免使用instanceof……事实上,我使用instanceof是因为我很懒,但我可以在没有任何instanceof的情况下,以访问者/站场方式做同样的事情……在你的示例中,你怎么会有木腿和普通腿的总和?@Jeff Forster,Simple,由于Pirate
类有一个getWoodLegNumber()
方法,因此WoodLegCounterVisitor
将只访问任何属于海盗的内容。我想了解的是,您的访问者实现不能同时具有海盗和人类的行为(没有类型转换),因为您只有一个访问方法。我当时的印象是,摆脱字体铸造是一件好事。我可能没有清楚地表达我的观点。您的访问者有一个单一的访问方法。这是不好的,因为通常情况下,您希望不同对象具有不同的行为。也许您只是指出了一种在这种特定情况下缩短代码的方法,但一般来说,为访问者提供单一方法并不是一件好事。关于许多未实现的方法,我确实同意你的观点,这就是为什么通常会有一个“VisitorAdapter”类提供空实现(类似于Swing函数)的原因,Jeff Forster在上一篇评论中提到了这个原因。我只是在学习访问者,这是一个混乱的模式实现,因为它只有一个单一的访问方法。
public interface MammalVisitor<T extends Mammal> {
public void visit(T mammal);
}
public class LegCounterVisitor implements MamalVisitor<Human> {
private int legNumber = 0;
@Override
public void visit(Human mammal) { legNumber += mammal.getLegsNumber(); }
public int getLegNumber() { return legNumber; }
}
public class WoodLegCounterVisitor implements MamalVisitor<Pirate> {
private int legNumber = 0;
@Override
public void visit(Pirate mammal) {legNumber += mammal.getWoodLegNumber(); }
public int getLegNumber() { return legNumber; }
}