title: Visitor on a business object in the domain in hexagonal/onion architecture?
body: <p>I'm using hexagonal architecture and I wonder how a visitor pattern would respect it ?</p>
  
  <p>The visited object is a domain object, but the visitor aims to dynamically dispatch said domain object implementations to appropriate mappers between domain object and data transfert object. </p>
  
  <p>My first thought would be to expose the abstraction of the visitor into domain and leave its actual implementations into infra, similar to a repository. </p>
  
  <p>Isn't it revealing infra into domain ? Visitor pattern is implementation details, right ? It doesn't bring any business value, so it doesn't belong to domain, isn't it ? However I need the accept method into my business object to achieve this pattern.</p>
  
  <p>What are you thoughts about it ?</p>
  
  <p>EDIT Code example (C# syntax but nothing fancy): </p>
  
  <pre><code>namespace Domain
  {
      public interface IFlow
      {
          void Accept(IFlowVisitor visitor);
      }
  
      public class Cashflow : IFlow
      {
          void Accept(IFlowVisitor visitor)
          {
              visitor.Visit(this);
          }
  
          // some properties
      }
  
      public class Assetflow : IFlow
      {
          void Accept(IFlowVisitor visitor)
          {
              visitor.Visit(this);
          }
  
          // some properties
      }
  
      public interface IFlowVisitor
      {
          void Visit(Assetflow flow);
          void Visit(Cashflow flow);
      }
  }
  
  namespace Infra
  {
      public class FlowVisitor : IFlowVisitor
      {
          public FlowVisitor(ICashflowMapper cashflowMapper, IAssetflowMapper assetflowMapper, IDao dao)
          {
              CashflowMapper = cashflowMapper;
              AssetflowMapper = assetflowMapper;
              Dao = dao;
          }
  
          private readonly ICashflowMapper CashflowMapper {get; set;}
          private readonly IAssetflowMapper AssetflowMapper {get; set;}
          private readonly IDao Dao {get; set;}
  
          public void Visit(Assetflow flow)
          {
              Assetflow assetflowDto = AssetflowMapper.Map(flow);
              dao.Persist(assetflowDto);
          }
  
          public void Visit(Cashflow flow)
          {
              CashflowDto cashflowDto = CashflowMapper.Map(flow);
              dao.Persist(cashflowDto);
          }
      }
  
      public interface ICashflowMapper
      {
          CashflowDto Map(Cashflow domainObject);
      }
  
      public interface IAssetflowMapper
      {
          AssetflowDto Map(Assetflow domainObject);
      }
  
      public interface IDao
      {
          void Persist(CashflowDto dto);
          void Persist(AssetflowDto dto);
      }
  
      public class cashflowDto 
      {
          // property bag
      }
      public class assetflowDto
      {
          // property bag
      }
  
      public class Test
      {
          public void TestMethod()
          {
              ICashflowMapper cashflowMapper = new CashflowMapper();
              IAssetflowMapper assetflowMapper = new AssetflowMapper();
              IDao dao = new Dao();
              IFlowVisitor visitor = new FlowVisitor(cashflowMapper, assetflowMapper, dao)
              List&lt;IFlow&gt; flows = new List&lt;IFlow&gt; { new Assetflow(), new Cashflow(), new Assetflow() };
  
              foreach(var flow in flows)
              {
                  flow.Accept(visitor);
              }
          }
      }
  }
  </code></pre>