Visitor Pattern solution: few visitors have same interface but should work with different objects

前端 未结 4 1016
梦毁少年i
梦毁少年i 2021-01-20 04:31

I have following class diagram (visitor pattern implementation):

Expected result:
1) WiredVisitor should visit only Router and WiredNetworkCard
2)

相关标签:
4条回答
  • 2021-01-20 04:55

    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.

    0 讨论(0)
  • 2021-01-20 04:59

    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);
          }
      }
      
    0 讨论(0)
  • 2021-01-20 05:05

    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.

    0 讨论(0)
  • 2021-01-20 05:17

    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

    0 讨论(0)
提交回复
热议问题