0

当目标对象时excelColumnspdfColumns部分共享相同的对象,其中一些甚至有条件地共享,什么是一个好的 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);
4

2 回答 2

0

您可以对最后一个共享列部分使用addAll(...)方法来add(...)为每个集合添加它们。如果您的目标是保持插入下一列的条件顺序,则没有必要对其进行混淆,因为这里已经清楚地呈现了。

于 2020-10-31T10:09:52.957 回答
0

根据您对复杂性的偏好,您可以执行以下操作:

  1. 尝试将相关列实例分组为对象,如HeaderColumns,BodyColumns等。
  2. 实现这里描述的访问者模式。

这是遵循上述建议的模式的可能实现:

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()`
}

这种方法的优点:

  1. 每次您必须向 中添加新报告部分时Visitor,都会在所有访问者实现中生成编译错误。这避免了人们忘记向ifswitch语句添加分支的典型编程错误。
  2. 如何构建报表的条件逻辑放在报表的实际实现中。不再需要有条件的。

这种方法的缺点:

  1. 鉴于您将需要创建额外的抽象,肯定会带来复杂性。
  2. 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; }
}
于 2020-10-31T11:02:11.430 回答