使用访客模式访问可访问对象对

问题描述 投票:0回答:2

是否有一种干净的模式允许访问者一次访问两个可访问对象?

例如,如果我的访问者是二进制加法运算符,它需要知道两个可访问输入的数据类型。

我在下面提供了一个解决方案,但感觉它很混乱,因为它要求所有可访问对象都包含所有具体可访问对象的重载,并且还要求访问者包含虚拟访问来解析 r-visitable。

如果访客模式不适合此目的,是否还有其他更适合的模式?

谢谢你

using System;
using System.Diagnostics;

namespace VisitorTest
{

   class Program
   {

      static void Main(string[] args)
      {

         // Given two visitable objects...
         IVisitable stringVisitable = new StringVisitable("987");
         IVisitable numberVisitable = new NumberVisitable(123);

         // And a visitor that performs a "lVisitable + rVisitable" operation...
         PlusOpVisitor plusOpVisitor = new PlusOpVisitor();

         // Test "string + string" == "987987"
         Console.WriteLine
         (  stringVisitable.PairAccept
            (  plusOpVisitor
            ,  stringVisitable
            )
         );

         // Test "string + number" == (convert both to string) == "987123"
         Console.WriteLine
         (  stringVisitable.PairAccept
            (  plusOpVisitor
            ,  numberVisitable
            )
         );

         // Test "number + string" == (convert both to number) == #1110
         Console.WriteLine
         (  numberVisitable.PairAccept
            (  plusOpVisitor
            ,  stringVisitable
            )
         );

         // Test "number + number" == #246
         Console.WriteLine
         (  numberVisitable.PairAccept
            (  plusOpVisitor
            ,  numberVisitable
            )
         );

      }

   }

   interface IPairVisitor
   {  // Messy: Dummies, just to know the l-visitable type, while visiting the r-visitable
      IVisitable Visit(StringVisitable lVisitable, IVisitable rVisitable);
      IVisitable Visit(NumberVisitable lVisitable, IVisitable rVisitable);
      // Actual visitor operations, what to do in each case
      IVisitable Visit(StringVisitable lVisitable, StringVisitable rVisitable);
      IVisitable Visit(NumberVisitable lVisitable, StringVisitable rVisitable);
      IVisitable Visit(StringVisitable lVisitable, NumberVisitable rVisitable);
      IVisitable Visit(NumberVisitable lVisitable, NumberVisitable rVisitable);
   }

   interface IVisitable
   {  // Resolve the l-visitable, include the unresolved r-visitable
      IVisitable PairAccept(IPairVisitor visitor, IVisitable  rVisitable);
      // Messy: Resolve the r-visitable, include the previously resolve l-visitable
      // The visitable-object must know the type of all objects that it can be
      // accepted against (normal visitor pattern doesn't have this restriction)
      IVisitable PairAccept(IPairVisitor visitor, StringVisitable lVisitable);
      IVisitable PairAccept(IPairVisitor visitor, NumberVisitable lVisitable);
   }

   class PlusOpVisitor : IPairVisitor
   {  // Repeat the accept, but for the other visitable
      public IVisitable Visit
      (  StringVisitable lVisitable
      ,  IVisitable      rVisitable
      ){ return rVisitable.PairAccept(this, lVisitable);
      }
      public IVisitable Visit
      (  NumberVisitable lVisitable
      ,  IVisitable      rVisitable
      ){ return rVisitable.PairAccept(this, lVisitable);
      }
      // Perform the actual operation for each pair
      public IVisitable Visit
      (  StringVisitable lVisitable
      ,  StringVisitable rVisitable
      ){ return new StringVisitable
         (  string.Concat
            (  lVisitable.Value
            ,  rVisitable.Value
            )
         );
      }
      public IVisitable Visit
      (  StringVisitable lVisitable
      ,  NumberVisitable rVisitable
      ){ return new StringVisitable
         (  string.Concat
            (  lVisitable.Value
            ,  rVisitable.Value.ToString()
            )
         );
      }
      public IVisitable Visit
      (  NumberVisitable lVisitable
      ,  StringVisitable rVisitable
      ){ return new NumberVisitable
         (  lVisitable.Value
          + int.Parse(rVisitable.Value)
         );
      }
      public IVisitable Visit
      (  NumberVisitable lVisitable
      ,  NumberVisitable rVisitable
      ){ return new NumberVisitable
         (  lVisitable.Value
          + rVisitable.Value
         );
      }
   }

   class StringVisitable : IVisitable
   {  public StringVisitable
      (  string value
      ){ _value = value;
      }
      public string Value
      {  get { return _value; }
      }
      // Visit as an l-visitable, r-visitable still unresolved
      public IVisitable PairAccept
      (  IPairVisitor  visitor
      ,  IVisitable rVisitable
      ){ return visitor.Visit(this, rVisitable);
      }
      // Visit as an r-visitable, l-visitable resolved
      public IVisitable PairAccept
      (  IPairVisitor       visitor
      ,  StringVisitable lVisitable
      ){ return visitor.Visit(lVisitable, this);
      }
      public IVisitable PairAccept
      (  IPairVisitor       visitor
      ,  NumberVisitable lVisitable
      ){ return visitor.Visit(lVisitable, this);
      }
      public override string ToString()
      {  return string.Concat("\"", _value, "\"");
      }
      private string _value;
   }

   class NumberVisitable : IVisitable
   {  public NumberVisitable
      (  int value
      ){ _value = value;
      }
      public int Value
      {  get { return _value; }
      }
      public IVisitable PairAccept
      (  IPairVisitor  visitor
      ,  IVisitable rVisitable
      ){ return visitor.Visit(this, rVisitable);
      }
      public IVisitable PairAccept
      (  IPairVisitor       visitor
      ,  StringVisitable lVisitable
      ){ return visitor.Visit(lVisitable, this);
      }
      public IVisitable PairAccept
      (  IPairVisitor       visitor
      ,  NumberVisitable lVisitable
      ){ return visitor.Visit(lVisitable, this);
      }
      public override string ToString()
      {  return string.Concat("#", _value);
      }
      private int _value;
   }

}
c# design-patterns visitor-pattern
2个回答
0
投票

看起来您实际上正在寻找 解释器模式。您可能还想查看表达式树


0
投票

这可以使用典型的访问者模式来实现,但三重调度除外,其中创建一个访问者来单独解析 LHS,同时存储未解析的 RHS,然后创建另一个访问者来解析 RHS,同时存储已解析的 LHS。

using System;
using System.Diagnostics;

namespace VisitorTest
{

   class Program
   {

      static void Main(string[] args)
      {

         // Given two visitable objects...
         IAcceptor stringAcceptor = new StringAcceptor("987");
         IAcceptor numberAcceptor = new NumberAcceptor(123);

         // And a visitor that performs a "lVisitable + rVisitable" operation...
         PlusOpVisitor plusOpVisitor = new PlusOpVisitor();

         // Test "string + string" == "987987"
         Console.WriteLine
         (  plusOpVisitor.Visit
            (  stringAcceptor
            ,  stringAcceptor
            )
         );

         // Test "string + number" == (convert both to string) == "987123"
         Console.WriteLine
         (  plusOpVisitor.Visit
            (  stringAcceptor
            ,  numberAcceptor
            )
         );

         // Test "number + string" == (convert both to number) == #1110
         Console.WriteLine
         (  plusOpVisitor.Visit
            (  numberAcceptor
            ,  stringAcceptor
            )
         );

         // Test "number + number" == #246
         Console.WriteLine
         (  plusOpVisitor.Visit
            (  numberAcceptor
            ,  numberAcceptor
            )
         );

      }

   }

   // Typical visitor/acceptor, no strong typing exposed
   interface IVisitor
   {  IAcceptor Visit(StringAcceptor acceptor);
      IAcceptor Visit(NumberAcceptor acceptor);
   }

   interface IAcceptor
   {  IAcceptor Accept(IVisitor visitor);
   }

   class PlusOpVisitor
   {

      public IAcceptor Visit(IAcceptor lAcceptor, IAcceptor rAcceptor)
      {  return lAcceptor.Accept(new LHSVisitor(rAcceptor));
      }

      // Visitor to handle the left-hand-side, holding the right-hand-side
      //  until the LHS is resolvd
      private class LHSVisitor : IVisitor
      {

         public LHSVisitor(IAcceptor rAcceptor)
         {  _rAcceptor = rAcceptor;
         }

         // With the LHS resolved, create a new visitor to handle the RHS
         //  storing the resolve LHS
         public IAcceptor Visit(StringAcceptor lAcceptor)
         {  return _rAcceptor.Accept(new LHSStringRHSVisitor(lAcceptor));
         }

         public IAcceptor Visit(NumberAcceptor lAcceptor)
         {  return _rAcceptor.Accept(new LHSNumberRHSVisitor(lAcceptor));
         }

         private readonly IAcceptor _rAcceptor;


      }

      // Visitor to handle the RHS when the LHS has been resolved as a string
      private class LHSStringRHSVisitor : IVisitor
      {

         public LHSStringRHSVisitor(StringAcceptor lAcceptor)
         {  _lAcceptor = lAcceptor;
         }

         // Now both LHS and RHS are resolved
         public IAcceptor Visit(StringAcceptor rAcceptor)
         {  return new StringAcceptor
            (  string.Concat(_lAcceptor.Value, rAcceptor.Value)
            );
         }

         public IAcceptor Visit(NumberAcceptor rAcceptor)
         {  return new StringAcceptor
            (  string.Concat(_lAcceptor.Value, rAcceptor.Value.ToString())
            );
         }

         private readonly StringAcceptor _lAcceptor;

      }

      private class LHSNumberRHSVisitor : IVisitor
      {

         public LHSNumberRHSVisitor(NumberAcceptor lAcceptor)
         {  _lAcceptor = lAcceptor;
         }

         public IAcceptor Visit(StringAcceptor rAcceptor)
         {  return new NumberAcceptor
            (  _lAcceptor.Value + int.Parse(rAcceptor.Value)
            );
         }

         public IAcceptor Visit(NumberAcceptor rAcceptor)
         {  return new NumberAcceptor(_lAcceptor.Value + rAcceptor.Value);
         }

         private readonly NumberAcceptor _lAcceptor;

      }

   }

   class StringAcceptor : IAcceptor
   {  public StringAcceptor
      (  string value
      ){ _value = value;
      }
      public string Value
      {  get { return _value; }
      }
      public IAcceptor Accept(IVisitor visitor)
      {  return visitor.Visit(this);
      }
      public override string ToString()
      {  return string.Concat("\"", _value, "\"");
      }
      private string _value;
   }

   class NumberAcceptor : IAcceptor
   {  public NumberAcceptor
      (  int value
      ){ _value = value;
      }
      public int Value
      {  get { return _value; }
      }
      public IAcceptor Accept(IVisitor visitor)
      {  return visitor.Visit(this);
      }
      public override string ToString()
      {  return string.Concat("#", _value);
      }
      private int _value;
   }

}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.