我正在寻找从通用框架调用特定接口的良好替代方案。我用代码来举例说明。看看问题部分,包含示例代码主要是为了彻底性,并将示例应用到实际场景中。
Example
假设我们想要基于组件列表构建报告。假设我们有两种特定的组件类型:
public interface Component { ... }
public class PDFComponents extends Component { ... }
public class WordComponents extends Component { ... }
每个组件都有一个 ReportBuilder 实现,例如,
public interface ReportBuilder { ... }
public class PDFReportBuilder extends ReportBuilder { ... }
public class WordReportBuilder extends ReportBuilder { ... }
哪个构建具体的报告实现
public interface Report { ... }
public class PDFReport extends ReportBuilder { ... }
public class WordReport extends ReportBuilder { ... }
最后,我们提供了定位组件并根据组件生成报告的服务。
public class ReportService {
ReportComponentRepository repo;
List<ReportBuilder> builders;
public <T extends Report> T getReport(Class<T> reportType) {
// Get report components. E.g., this might return List<PDFComponent>
List<Component> reportComponents = repo.getReportComponents(id);
// Build report from components using one of the registered builders
for (ReportBuilder builder : builders) {
if (builder.buildFor(reportType) {
return builder.buildReport(report);
}
}
}
}
使用服务的示例
List<PDFReport> reports = new ReportService().getReport(PDFReport.class);
Question
现在回答问题。如何设计一个通用的 ReportBuilder 接口,使其实现具有类型安全性?
例如,选择接口:
public Report buildReport(List<? extends Component> components);
会导致其实现的丑陋:
public class PDFReportBuilder implements ReportBuilder {
@Override
public Report buildReport(List<? extends Component> components) {
PDFReport report;
for (Component component : components) {
if (component instanceOf PDFComponent) {
// assemble report ...
report.includeComponent(component);
}
}
return report;
}
}
当我们真正希望 PDFReportBuilder 的界面为例如:
public Report buildReport(List<PDFComponent> component) { ... }