您的问题的一般情况称为双重分派 - 您需要根据两个参数的运行时类型分派到一个方法,而不仅仅是一个参数(“this”指针)。
处理此问题的一种标准模式称为访问者模式。它的描述可以追溯到最初的设计模式书籍,因此有很多示例和分析。
基本思想是,您有两个一般事物 - 您有元素(即您正在处理的事物)和访问者,它们对元素进行处理。您需要对它们进行动态分派 - 因此调用的实际方法会根据元素和访问者的具体类型而有所不同。
在 C# 中,有点像您的示例,您可以定义一个 IFeatureVisitor 接口,如下所示:
public interface IFeatureVisitor {
void Visit(ChartFeature feature);
void Visit(ListFeature feature);
// ... etc one per type of feature
}
然后,在 IFeature 界面中添加“Accept”方法。
public interface IFeature {
public void Accept(IFeatureVisitor visitor);
}
您的功能实现将实现 Accept 方法,如下所示:
public class ChartFeature : IFeature {
public void Accept(IFeatureVisitor visitor) {
visitor.Visit(this);
}
}
然后,您的报告编写者将实现 IVisitor 接口并执行每种类型中应执行的操作。
要使用它,它看起来像这样:
var writer = new HtmlReportWriter();
foreach(IFeature feature in document) {
feature.Accept(writer);
}
writer.FinishUp();
其工作方式是对 Accept 的第一个虚拟调用解析回该功能的具体类型。对 Visit 方法的调用不是虚拟的 - 调用visitor.Visit(this)
调用正确的重载,因为此时它知道正在访问的事物的确切静态类型。不保留任何强制转换和类型安全。
当添加新的访问者类型时,这种模式非常有用。当元素(您的情况下的功能)发生变化时,情况会更加痛苦 - 每次添加新元素时,您都需要更新 IVisitor 接口和所有实现。所以要慎重考虑。
正如我提到的,这本书出版已经快 20 年了,所以你可以在书中找到很多关于 Visitor 模式的分析和改进。很有帮助的是,这为您提供了足够的开始来继续您的分析。