Use Factory method pattern:
public enum ReportType {EXCEL, CSV};
@Service
public class ReportFactory {
@Resource
private ExcelReport excelReport;
@Resource
private CSVReport csvReport
public Report forType(ReportType type) {
switch(type) {
case EXCEL: return excelReport;
case CSV: return csvReport;
default:
throw new IllegalArgumentException(type);
}
}
}
The report type enum
can be created by Spring when you call your controller with ?type=CSV
:
class MyController{
@Resource
private ReportFactory reportFactory;
public HttpResponse getReport(@RequestParam("type") ReportType type){
reportFactory.forType(type);
}
}
However ReportFactory
is pretty clumsy and requires modification every time you add new report type. If the report types list if fixed it is fine. But if you plan to add more and more types, this is a more robust implementation:
public interface Report {
void generateFile();
boolean supports(ReportType type);
}
public class ExcelReport extends Report {
publiv boolean support(ReportType type) {
return type == ReportType.EXCEL;
}
//...
}
@Service
public class ReportFactory {
@Resource
private List<Report> reports;
public Report forType(ReportType type) {
for(Report report: reports) {
if(report.supports(type)) {
return report;
}
}
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
With this implementation adding new report type is as simple as adding new bean implementing Report
and a new ReportType
enum value. You could get away without the enum
and using strings (maybe even bean names), however I found strongly typing beneficial.
Last thought: Report
name is a bit unfortunate. Report
class represents (stateless?) encapsulation of some logic (Strategy pattern), whereas the name suggests it encapsulates value (data). I would suggest ReportGenerator
or such.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…