我正在寻找从通用框架调用特定接口的替代方法。我将以代码为例。看 问题部分 ,主要包括示例代码,以确保透彻性,并将示例置于真实场景中。
假设我们要基于组件列表构建报告。假设我们有两种特定的组件类型:
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);
现在到问题。如何设计允许其类型安全的通用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) { ... }
如果将Component的类型设置为ReportBuilder的类型变量,它将起作用:
public interface ReportBuilder<T extends Component> { public Report buildReport(List<T> components); } public class PDFReportBuilder implements ReportBuilder<PDFComponent> { public Report buildReport(List<PDFComponent> components); }
不过,您必须评估您是否真的想要ReportBuilder中的类型变量。这并不总是正确的选择。此外,如果您还希望PDFReportBuilder.buildReport返回类型为PDFReport,则还需要将其作为类型变量(即public interface ReportBuilder<T extends Component, S extends Report>)。
PDFReportBuilder.buildReport
public interface ReportBuilder<T extends Component, S extends Report>