I've come to a road block in my application architecture. I've just started using the visitor pattern to execute specific algos on abstract objects of which type I don't know at runtime. My problem is that my algo also depends on the type of a nested abstract type as well.
Let me illustrate what I mean:
I have an abstract DataSource class. From this I implement concerete DataSourceReference and DataSourceExplicit classes. I also have an abstract Report class (the deserialized metadata), from which I implement concrete Report classes ReportTypeA and ReportTypeB. When these objects are created, their DataSource may be any extending DataSource class.
I need both, the actual Report type and DataSource type so I can execute accordingly. I can get the concerte Report type using the visitor pattern, but don't know how to do the same for DataSource afterwards/also.
I can't visit DataSource after visiting Report, because I'd lose the concrete type of Report (as you would have to let it accept the base Report type: Accept(SomeDataSourceVisitor d, MetaReport m) - or overload for every possible Report type, which defeats the purpose of Visitor Pattern. See my problem?
Any ideas? I'd like to stay away from using dynamic, as it wouldn't require developers of new Report types to make sure the dispatcher(visitor) supports the new Report.
Current Code:
public abstract class DataSource
{
}
public class DataSourceReference : DataSource
{
// reference thing(s)
}
public class DataSourceExplicit : DataSource
{
// explicit thing(s)
}
public abstract class Report
{
// some shared Report attribute(s)
// ...
public DataSource DataSource { get; set; }
public abstract FinalReport Execute(IReportExecutionDispatcher d);
}
public class ReportA : Report
{
// ReportA specific attribute(s)
// ...
public override Execute(IReportExecutionDispatcher d)
{
d.ExecuteReport(this);
}
}
public class ReportB : Report
{
// ReportB specific attribute(s)
// ...
public override Execute(IReportExecutionDispatcher d)
{
d.ExecuteReport(this);
}
}
public interface IReportExecutionDispatcher
{
FinalReport ExecuteReport(ReportA);
FinalReport ExecuteReport(ReportB);
}