문제

I was doing some homework today with the visitor-pattern, and i made a visitor that looked somewhat like this (edited sample code from wikipedia):

class CarElementPrintVisitor implements CarElementVisitor {
    public void visit(CarElement element) {      
        if (element.getClass() == Wheel.class)
        {
            return visit((Wheel)element);
        }
        else if (element.getClass() == Engine.class)
        {
            return visit((Engine)element);
        }
        else if (element.getClass() == Body.class)
        {
            return visit((Body)element);
        }
        else //if (v.getClass() == Car car.class)
        {
            return visit((Car)element);
        }
    }

    public void visit(Wheel wheel) {      
        System.out.println("Visiting " + wheel.getName() + " wheel");
    }

    public void visit(Engine engine) {
        System.out.println("Visiting engine");
    }

    public void visit(Body body) {
        System.out.println("Visiting body");
    }

    public void visit(Car car) {      
        System.out.println("Visiting car");
    }
}

The "public void visit(CarElement element)" method is kind of ugly (long and needs to be maintained if more CarElements are added) but i want to keep the method, so i tried to do it better.

I ended up trying this out:

    public void visit(CarElement element) {      
        return visit(element.getClass().cast(element));
    }

But that just returns "visit(CarElement element)", even though element.getClass() returns the correct class, so it ends up in a infinite loop.

Does anyone know how to do, what i'm trying to do? (If it is even possible, i'm not sure).

도움이 되었습니까?

해결책

You missed what makes the beauty of the visitor pattern: the accept(CarElementVisitor) method that must be in the CarElement interface, and which calls the visitor back with itself, using the approriate type. Re-read the wikipedia article.

다른 팁

Your problem with last version is that you try to use overloading during run-time which Java doesn't support. Java can dispatch call to various implementations based on type of object whose method is called, not on the type of argument.

Here's sample of Visitor pattern which will work as you (hopefully) want:

class EventA {
    void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class EventB {
    void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

interface Visitor {
    void visit(EventA e);
    void visit(EventB e);
}

class VisitorImpl implements Visitor {
    public void visit(EventA e) {
        System.out.println("EventA");
    }

    public void visit(EventB e) {
        System.out.println("EventB");
    }
}

public class Main {

    public static void main(String[] args) {
        EventA event = new EventA();
        event.accept(new VisitorImpl());
    }

}

Note that you still need to extend Visitor interface every time you add new types to visit. And see this answer of mine.

Hope, this helps a bit )

You can have an abstract method on CarElement.

public abstract void visit();

class Wheel extends CarElement {
    public void visit() {
        System.out.println("Visiting " + getName() + " wheel");
    }
}

CarElement ce = new Wheel();
ce.visit();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top