问题描述
当目标对象excelColumns
,pdfColumns
部分共享相同的对象,甚至有条件地共享其中的一些对象时,什么是使函数式编程,紧密耦合和样板无效的良好OOP模式?假设有很多共享列,只有少数非共享列和条件列。
List<Column> excelColumns = new ArrayList<>();
List<Column> pdfColumns = new ArrayList<>();
//shared columns
Column test = new Column("test",121,11);
excelColumns.add(test);
pdfColumns.add(test);
//conditional columns
if (condition) {
excelColumns.add(new Column("test2",12,21));
}
//non shared columns
pdfColumns.add(new Column("test3",41));
//shared columns
Column test4 = new Column("test4",331);
excelColumns.add(test4);
pdfColumns.add(test4);
Column test5 = new Column("test5",72,11);
excelColumns.add(test5);
pdfColumns.add(test5);
Column test6 = new Column("test6",82,121);
excelColumns.add(test6);
pdfColumns.add(test6);
解决方法
对于最后一个共享列部分,您可以使用addAll(...)
方法而不是add(...)
来为每个集合都添加它们。如果您的目标是保持插入下一列的条件顺序,则没有必要对其进行混淆,因为此处已将其清楚地显示出来。
根据您对复杂性的需求,可以执行以下操作:
- 尝试将相关的列实例分组为
HeaderColumns
,BodyColumns
等对象。 - 按照here的描述实施访客模式。
以下是根据上述建议可能实现的模式:
public class Main {
interface Visitor {
void visit(ReportHeader header);
void visit(ReportBody body);
}
interface Visitable {
void accept(Visitor visitor);
}
static class ReportHeader implements Visitable {
private final List<String> columns = new ArrayList<>();
private final List<String> extras = new ArrayList<>();
@Override
public void accept(Visitor visitor) { visitor.visit(this); }
public List<String> getColumns() { return columns; }
public List<String> getExtras() { return extras; }
}
static class ReportBody implements Visitable {
private final List<String> columns = new ArrayList<>();
@Override
public void accept(Visitor visitor) { visitor.visit(this); }
public List<String> getColumns() { return columns; }
}
static class ExcelReportVisitor implements Visitor {
private final List<String> columns = new ArrayList<>();
@Override
public void visit(ReportHeader header) {
columns.addAll(header.getColumns());
columns.addAll(header.getExtras());
}
@Override
public void visit(ReportBody body) { columns.addAll(body.getColumns()); }
}
static class PdfReportVisitor implements Visitor {
private final List<String> columns = new ArrayList<>();
@Override
public void visit(ReportHeader header) {
columns.addAll(header.getColumns());
// no extras for PDF
}
@Override
public void visit(ReportBody body) { columns.addAll(body.getColumns()); }
}
}
您可以按以下方式使用它:
public static void main(String args[]) {
ReportHeader header = new ReportHeader();
ReportBody body = new ReportBody();
List<Visitor> visitors = Arrays.asList(new PdfReportVisitor(),new ExcelReportVisitor());
visitors.forEach(each -> {
each.visit(header);
each.visit(body);
});
// do something with the visitors like `visitor.exportReport()`
}
这种方法的优点:
- 每次您必须向
Visitor
添加新的报告部分时,都会在所有访问者实现中生成编译错误。这样可以避免人们忘记为if
或switch
语句添加分支的典型编程错误。 - 有关如何构建报告的条件逻辑位于报告的实际实现中。不再需要条件。
这种方法的缺点:
- 请确保您需要创建其他抽象的复杂性。
- 有时,将
Column
实例封装/分组为语义上有凝聚力的对象可能是没有意义的,也可能是不可能的。例如,您可能在ReportHeader
中以这样的怪异结尾:
static class ReportHeader implements Visitable {
private final List<String> columns = new ArrayList<>();
private final List<String> extras = new ArrayList<>();
private final List<String> dataThatIsOnlyUsedByExcelReport = new ArrayList<>();
@Override
public void accept(Visitor visitor) { visitor.visit(this); }
public List<String> getColumns() { return columns; }
public List<String> getExtras() { return extras; }
public List<String> getDataThatIsOnlyUsedByExcelReport() { return dataThatIsOnlyUsedByExcelReport; }
}