访客模式解决方案:很少访问者具有相同的界面,但应该使用不同的对象

我有以下类图(访问者模式实现):

在此处输入图像描述

预期结果:
1)WiredVisitor应该只访问Router和WiredNetworkCard
2)WirelessVisitor只能访问Router和WirelessNetworkCard

所以,我的问题是:我应该如何改变设计(或代码)以实现我的预期结果?

PS我目前的解决方案是在两个访问者中为每次访问(卡:INetworkCard)方法添加以下代码:

// 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 } 

本着非循环访问者模式的精神,将访问者分成特定的子类。 请注意,您仍然需要进行类型检查,但它包含在被访问的类型中:

以下是访客界面:

 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); } 

具体访问者将如下所示:

 class WiredVisitor implements IWiredNetworkCardVisitor, IRouterVisitor { // ... } class WirelessVisitor implements IWirelessNetworkCardVisitor, IRouterVisitor { // ... } 

和访问过的对象:

 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); } } } 

在这些类型检查中,如果类型不是预期的类型,您也可以抛出错误,具体取决于您希望在这种情况下发生的情况。

你可以这样做:

 public interface IVisitor { public void visit( T card ); } 

然后你将访客定义为:

 public class WiredVisitor implements IVisitor { ... } public class WirelessVisitor implements IVisitor { ... } 

这可能不是教科书的解决方案,但它非常干净且非常易读。

我认为这里的问题不在于访问者,而是当客户端通过传递WirelessVisitor来调用WiredNetworkCard ,这是一个错误。 然后应该通过在那个时间点引发exception来处理它。

但所有这些都在运行时发生,而biziclop的解决方案在编译时自行处理它。 但我不喜欢biziclop的解决方案是实现IVisitor也会visit(router:Router)方法,这与WiredNetworkCard没有任何关系

你可以在你希望它访问的每个元素集上定义一些接口并拍一个接口……这样做的好处是:

  • 它是类型安全的
  • 没有运行时检查(因为它们不需要); 没有运行时exception

这是我为你的例子所说的实现:

  • 游客:

     interface Wired {  R accept(Visitor v); interface Visitor { R visit(Router router); R visit(WiredNetworkCard wiredNetworkCard); } } interface Wireless {  R accept(Visitor v); interface Visitor { R visit(Router router); R visit(WirelessNetworkCard wirelessNetworkCard); } } 
  • 内容:

     class Router implements Wired, Wireless { @Override public  R accept(Wired.Visitor v) { return v.visit(this); } @Override public  R accept(Wireless.Visitor v) { return v.visit(this); } } class WiredNetworkCard implements Wired { @Override public  R accept(Wired.Visitor v) { return v.visit(this); } } class WirelessNetworkCard implements Wireless { @Override public  R accept(Wireless.Visitor v) { return v.visit(this); } }