问题
I have following class diagram (visitor pattern implementation):
Expected result:
1) WiredVisitor should visit only Router and WiredNetworkCard
2) WirelessVisitor should visit only Router and WirelessNetworkCard
So, my question is: How should I change design (or code) for achieving my expected result?
P.S. My current solution is to add following piece of code to each visit(card:INetworkCard) method in both visitors:
// in WiredVisitor
if (card.getClass.equals(WiredNetworkCard.class)){
// do logic of visit method
}
// in WirelessVisitor
if (card.getClass.equals(WirelessNetworkCard.class)){
// do logic of visit method
}
回答1:
In the spirit of the acyclic visitor pattern, separate your visitors into subclass specific ones. Note that you'll still need the type check, but it's contained to the type being visited:
Here are the visitor interfaces:
interface IVisitor {
}
interface IRouterVisitor extends IVisitor {
void visit(Router router);
}
interface INetworkCardVisitor extends IVisitor {
}
interface IWirelessNetworkCardVisitor extends INetworkCardVisitor {
void visit(WirelessNetworkCard card);
}
interface IWiredNetworkCardVisitor extends INetworkCardVisitor {
void visit(WiredNetworkCard card);
}
The concrete visitors will look like this:
class WiredVisitor implements IWiredNetworkCardVisitor, IRouterVisitor {
// ...
}
class WirelessVisitor implements IWirelessNetworkCardVisitor, IRouterVisitor {
// ...
}
And the visited objects:
interface INetworkElement {
void accept(IVisitor visitor);
}
class Router implements INetworkElement {
@Override
public void accept(IVisitor visitor) {
if (visitor instanceof IRouterVisitor) {
((IRouterVisitor)visitor).visit(this);
}
}
}
interface INetworkCard extends INetworkElement {}
class WiredNetworkCard implements INetworkCard {
@Override
public void accept(IVisitor visitor) {
if (visitor instanceof IWiredNetworkCardVisitor) {
((IWiredNetworkCardVisitor)visitor).visit(this);
}
}
}
class WirelessNetworkCard implements INetworkCard {
@Override
public void accept(IVisitor visitor) {
if (visitor instanceof IWirelessNetworkCardVisitor) {
((IWirelessNetworkCardVisitor)visitor).visit(this);
}
}
}
In those type checks, you can also throw an error if the type is not the expected one, depending on what you'd like to happen in that case.
回答2:
You could do this for example:
public interface IVisitor<T extends INetworkCard> {
public void visit( T card );
}
And then you'd define your visitors as:
public class WiredVisitor implements IVisitor<WiredNetworkCard> {
...
}
public class WirelessVisitor implements IVisitor<WirelessNetworkCard> {
...
}
This may not be the textbook solution but it's very clean and very readable.
回答3:
I think the problem here is not with the Visitor but when the Client calls accept on WiredNetworkCard
by passing a WirelessVisitor
which is a bug. It should be handled then by raising an exception at that point in time.
But all this is happening at runtime and biziclop's solution handles it at compile time itself. But what I don't like about biziclop's solution is that WiredVisitor
which implements IVisitor<WiredNetworkCard>
will also have visit(router:Router)
method which is in no way related to WiredNetworkCard
回答4:
you can just define some interfaces and slap one on each of the sets of elements that you want it to visit...the advantages of doing it this way are:
- it is type safe
- no runtime checks (since they're not needed); no runtime exceptions
here is an implementation of what i'm talking about for your example:
visitors:
interface Wired { <R> R accept(Visitor<R> v); interface Visitor<R> { R visit(Router router); R visit(WiredNetworkCard wiredNetworkCard); } } interface Wireless { <R> R accept(Visitor<R> v); interface Visitor<R> { R visit(Router router); R visit(WirelessNetworkCard wirelessNetworkCard); } }
elements:
class Router implements Wired, Wireless { @Override public <R> R accept(Wired.Visitor<R> v) { return v.visit(this); } @Override public <R> R accept(Wireless.Visitor<R> v) { return v.visit(this); } } class WiredNetworkCard implements Wired { @Override public <R> R accept(Wired.Visitor<R> v) { return v.visit(this); } } class WirelessNetworkCard implements Wireless { @Override public <R> R accept(Wireless.Visitor<R> v) { return v.visit(this); } }
来源:https://stackoverflow.com/questions/11423217/visitor-pattern-solution-few-visitors-have-same-interface-but-should-work-with