我在应用程序架构中遇到了障碍。我刚刚开始使用访问者模式在抽象对象上执行特定的算法,这些抽象对象在运行时我不知道。 我的问题是我的算法也取决于嵌套抽象类型的类型。
我有一个抽象的DataSource类。从这里我实现了concerete DataSourceReference和DataSourceExplicit类。我还有一个抽象的Report类(反序列化的元数据),我从中实现具体的Report类ReportTypeA和ReportTypeB。创建这些对象时,它们的DataSource可以是任何扩展的DataSource类。
我需要两者,实际的Report类型和DataSource类型,所以我可以相应地执行。我可以使用访问者模式获取协同报告类型,但不知道如何对DataSource 进行后续/也。
访问Report后我无法访问DataSource,因为我丢失了具体的Report类型(因为你必须让它接受基本的Report类型:Accept(SomeDataSourceVisitor d,MetaReport m) - 或者每个都重载可能的报告类型,它违背了访客模式的目的。看到我的问题?
有什么想法吗?我不想使用动态,因为它不需要新报告类型的开发人员确保调度程序(访问者)支持新报告。
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);
}
答案 0 :(得分:3)
在搜索互联网时也发现了这一点。将其发布在此处以供将来参考和讨论。
时使用选择性访客模式
- 您正在使用支持多种分类的编程语言(理想情况下是方法重载)。
- 您希望对对象中的(可能不同的种类)元素执行不同类型的操作 结构。的
- 您希望避免使用与其基本职责无关的操作来污染元素类。
- 您希望能够轻松地在结构中添加新类型的元素,而不会影响其现有设计。
答案 1 :(得分:2)
您希望使用N * M方法,其中N是报告类型的计数,M是数据源类型的计数。我认为这里正确的方法是将它们分成N个类型,每个类型都有M个方法,加上一个辅助类型,这有助于我们在调度中迈出第一步。像这样:
public interface IDataSourceExecutionDispatcher
{
FinalReport ExecuteReport(DataSourceExplicit dataSource);
FinalReport ExecuteReport(DataSourceReference dataSource);
}
public interface IReportExecutionDispatcher
{
IDataSourceExecutionDispatcher GetDataSourceDispatcher(ReportA report);
IDataSourceExecutionDispatcher GetDataSourceDispatcher(ReportB report);
}
public class ReportExecutionDispatcher: IReportExecutionDispatcher
{
public IDataSourceExecutionDispatcher GetDataSourceDispatcher(
ReportA report)
{
return new ReportADataSourceExecutionDispatcher(report);
}
public IDataSourceExecutionDispatcher GetDataSourceDispatcher(
ReportB report)
{
return new ReportBDataSourceExecutionDispatcher(report);
}
}
class ReportADataSourceExecutionDispatcher : IDataSourceExecutionDispatcher
{
public ReportADataSourceExecutionDispatcher(ReportA report)
{
// save the report into a field
}
public FinalReport ExecuteReport(DataSourceExplicit dataSource)
{
// use saved report A and explicit dataSource here
}
public FinalReport ExecuteReport(DataSourceReference dataSource)
{
// similar, but with reference dataSource
}
}
class ReportBDataSourceExecutionDispatcher : IDataSourceExecutionDispatcher
{
// similar to ReportA dispatcher, except it takes ReportB in constructor
}
现在我们只需要修改我们的数据源以接受新的调度程序:
public abstract class DataSource
{
public abstract FinalReport Execute(IDataSourceExecutionDispatcher d);
}
public class DataSourceReference : DataSource
{
public override FinalReport Execute(IDataSourceExecutionDispatcher d)
{
return d.ExecuteReport(this);
}
}
并修改报告:
public abstract class Report
{
public DataSource DataSource { get; set; }
public abstract FinalReport Execute(IReportExecutionDispatcher d);
}
public class ReportA : Report
{
public override FinalReport Execute(IReportExecutionDispatcher d)
{
var dispatcher = d.GetDataSourceDispatcher(this);
return DataSource.Execute(dispatcher);
}
}