【问题标题】:java void functional programming, tight coupling and boilerplatejava void 函数式编程,紧耦合和样板
【发布时间】:2020-10-31 09:50:25
【问题描述】:

当目标对象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);

【问题讨论】:

    标签: java functional-programming boilerplate tightly-coupled-code


    【解决方案1】:

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

    1. 尝试将相关列实例分组为HeaderColumnsBodyColumns等对象。
    2. 按照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()`
    }
    

    这种方法的优点:

    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; }
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 感谢@marcin.programuje,但是如何避免excelColumnspdfColumns 之间的紧密耦合,假设我想在不同的类中实现?
      • 然后你就可以使用策略模式了。假设您希望将excelColumns 集合构建过程与pdfColumns 集合构建过程分开,您可以创建一个类ExcelColumnsBuildingStrategyPdfColumnsBuildingStrategy。两个类都将实现相同的接口ColumnsBuildingStrategy。更多信息在这里:tutorialspoint.com/design_pattern/strategy_pattern.htm
      猜你喜欢
      • 2017-05-09
      • 2013-12-25
      • 2021-09-10
      • 2022-07-06
      • 2015-05-12
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      相关资源
      最近更新 更多