Skip to main content
added 2 characters in body
Source Link
toolic
  • 16.4k
  • 6
  • 29
  • 221
public class TextTableTest {
    public static void main(String[] args) {
        new TextTableTest().testTablePrintOutput();
    }

    public void testTablePrintOutput() {
        Table table = new Table.Builder<>(MartinsExampleRow::new)
                .add(row -> row.x(1).y(2))
                .add(row -> row.x(1.2).y(2.3))
                .add(row -> row.firstName("peter").lastName("parker"))
                .add(row -> row.firstName("bruce").lastName("waytoolongname"))
                .add(row -> row.x(-2.44).y(3.1415).firstName("alfred"))
                .build();

        table.print();
    }
}
```
public class TextTableTest {
    public static void main(String[] args) {
        new TextTableTest().testTablePrintOutput();
    }

    public void testTablePrintOutput() {
        Table table = new Table.Builder<>(MartinsExampleRow::new)
                .add(row -> row.x(1).y(2))
                .add(row -> row.x(1.2).y(2.3))
                .add(row -> row.firstName("peter").lastName("parker"))
                .add(row -> row.firstName("bruce").lastName("waytoolongname"))
                .add(row -> row.x(-2.44).y(3.1415).firstName("alfred"))
                .build();

        table.print();
    }
}
```
public class TextTableTest {
    public static void main(String[] args) {
        new TextTableTest().testTablePrintOutput();
    }

    public void testTablePrintOutput() {
        Table table = new Table.Builder<>(MartinsExampleRow::new)
                .add(row -> row.x(1).y(2))
                .add(row -> row.x(1.2).y(2.3))
                .add(row -> row.firstName("peter").lastName("parker"))
                .add(row -> row.firstName("bruce").lastName("waytoolongname"))
                .add(row -> row.x(-2.44).y(3.1415).firstName("alfred"))
                .build();

        table.print();
    }
}
Source Link
Roman
  • 2.9k
  • 12
  • 23

I don't really have a code review. What I have is more of an idea.

Possum suggests that you can use a factory. However, I don't think a factory is particularly suitable for this use case. Because the more columns your table gets, the more confusing the creation of a TableRow becomes. Even with just three values, it can become confusing: new NamedPoint(-2.44, 3.1415, "alfred"). Is "alfred" the first name or the surname? Have I perhaps entered -2.44 and 3.1415 the wrong way round? To check this, I have to look into the constructor and check which argument belongs to which construct parameter depending on the position. This is still feasible with three values, but with 10 values it could be exhausting to check whether the values are specified correctly.

This is the reason I would instead recommend a builder:

var table = Table.builder(MartinsExampleRow::new)
 .add(row -> row.x(1).y(2))
 .add(row -> row.x(1.2).y(2.3))
 .add(row -> row.firstName("peter").lastName("parker"))
 .add(row -> row.firstName("bruce").lastName("waytoolongname"))
 .add(row -> row.x(-2.44).y(3.1415).firstName("alfred"))
 .build();

There are actually two builders. One builder for the table and one builder for the row. The builder for the row e.g. row.x(-2.44).y(3.1415).firstName("alfred") allows us to see immediately whether we have entered the values correctly. We do not have to check the constructor.


public class Table {
    private final List<TableRow> rows;

    private Table(List<TableRow> rows) {
        this.rows = rows;
    }

    public void print() {
        new TextTableFormatter(rows).createTableRows().forEach(System.out::println);
    }

    public static class Builder<T extends RowBuilder> {
        private final List<TableRow> rows = new ArrayList<>();
        private final Supplier<T> supplier;

        public Builder(Supplier<T> supplier) {
            this.supplier = supplier;
        }

        public Builder<T> add(Consumer<T> row) {
            row.andThen(x -> rows.add(x.build())).accept(supplier.get());
            return this;
        }

        public Table build() {
            return new Table(rows);
        }
    }

    public interface RowBuilder {
        TableRow build();
    }
}
class MartinsExampleRow implements Table.RowBuilder {
    private String firstName = "";
    private String lastName = "";
    private double x;
    private double y;

    public MartinsExampleRow firstName(String value) {
        this.firstName = value;
        return this;
    }

    public MartinsExampleRow lastName(String value) {
        this.lastName = value;
        return this;
    }

    public MartinsExampleRow x(double value) {
        this.x = value;
        return this;
    }

    public MartinsExampleRow y(double value) {
        this.y = value;
        return this;
    }

    @Override
    public TableRow build() {
        return () -> Map.of(
                "first name", firstName,
                "family", lastName,
                "x", Double.toString(x),
                "y", Double.toString(y)
        );
    }
}

public class TextTableTest {
    public static void main(String[] args) {
        new TextTableTest().testTablePrintOutput();
    }

    public void testTablePrintOutput() {
        Table table = new Table.Builder<>(MartinsExampleRow::new)
                .add(row -> row.x(1).y(2))
                .add(row -> row.x(1.2).y(2.3))
                .add(row -> row.firstName("peter").lastName("parker"))
                .add(row -> row.firstName("bruce").lastName("waytoolongname"))
                .add(row -> row.x(-2.44).y(3.1415).firstName("alfred"))
                .build();

        table.print();
    }
}
```