функциональное программирование java void, жесткая связь и шаблон

Когда целевые объекты excelColumns, pdfColumns частично используют одни и те же объекты, а некоторые из них даже условно, что является хорошим шаблоном ООП для отмены функционального программирования, жесткой связи и шаблонов, как в приведенном ниже коде? Предположим, что общих столбцов будет много, а не общих и условных - мало.

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

person partinis    schedule 31.10.2020    source источник


Ответы (2)


В зависимости от вашего желания усложнять, вы можете сделать следующее:

  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, он будет генерировать ошибку компиляции во всех реализациях посетителя. Это позволяет избежать типичных ошибок программирования, когда люди забывают добавлять ветки к операторам if или switch.
  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; }
}
person Trein    schedule 31.10.2020

Вы можете использовать метод addAll(...) вместо add(...) для последнего раздела общих столбцов, чтобы добавить их все для каждой коллекции. Если ваша цель - поддерживать условный порядок вставки следующих столбцов, нет смысла скрывать его, потому что здесь он четко представлен.

person marcin.programuje    schedule 31.10.2020
comment
спасибо @ marcin.programuje, но как аннулировать тесную связь между excelColumns и pdfColumns, скажем, я хочу иметь реализации в разных классах? - person partinis; 31.10.2020
comment
Затем вы можете использовать паттерн Стратегия. Предполагая, что вы хотите, чтобы excelColumns процесс построения коллекции был отделен от pdfColumns процесса построения коллекции, вы можете создать класс ExcelColumnsBuildingStrategy PdfColumnsBuildingStrategy. Оба класса будут реализовывать один и тот же интерфейс ColumnsBuildingStrategy. Дополнительная информация здесь: tutorialspoint.com/design_pattern/strategy_pattern.htm - person marcin.programuje; 31.10.2020