java void 函数式编程、紧耦合和样板
java void functional programming, tight coupling and boilerplate
当目标对象 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", 12, 41));
//shared columns
Column test4 = new Column("test4", 12, 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
语句添加分支的典型编程错误。
- 如何构建报表的条件逻辑放在报表的实际实现中。不再需要条件。
这种方法的缺点:
- 考虑到您需要创建的额外抽象,肯定会很复杂。
- 有时 encapsulate/group 您的
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; }
}
当目标对象 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", 12, 41));
//shared columns
Column test4 = new Column("test4", 12, 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
语句添加分支的典型编程错误。 - 如何构建报表的条件逻辑放在报表的实际实现中。不再需要条件。
这种方法的缺点:
- 考虑到您需要创建的额外抽象,肯定会很复杂。
- 有时 encapsulate/group 您的
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; }
}