Я ищу хорошие альтернативы вызову определенного интерфейса из универсального фреймворка. Я приведу пример с кодом. Посмотрите на часть вопроса , пример кода в основном включен для тщательности и для помещения примера в реальный сценарий.
Пример
Предположим, мы хотим построить отчет на основе списка компонентов. Скажем, у нас есть два конкретных типа компонентов:
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) { ... }