DEV Community

Illya Kysil
Illya Kysil

Posted on • Originally published at ikysil.github.io on

Implementing Fluent Builder with Functional Java 8

package playground;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.swing.*;

import static playground.JavaPlayground.Builder.of;

public class FunctionalBuilderDemo {

    static class Builder<T> {

        private final T instance;

        private Builder(final T instance) {
            Objects.requireNonNull(instance, "instance is required");
            this.instance = instance;
        }

        static <T> Builder<T> of(final T instance) {
            return new Builder<>(instance);
        }

        static <T> Builder<T> of(final Supplier<T> supplier) {
            return new Builder<>(supplier.get());
        }

        public Builder<T> with(final Consumer<T> c) {
            c.accept(instance);
            return this;
        }

        public <V> Builder<T> with(final BiConsumer<T, ? super V> c, final V value) {
            c.accept(instance, value);
            return this;
        }

        public <V> Builder<T> add(final Supplier<Collection<? super V>> c, final V value) {
            c.get().add(value);
            return this;
        }

        public <V> Builder<T> add(final Function<T, Collection<? super V>> c, final V v) {
            c.apply(instance).add(v);
            return this;
        }

        public <V> Builder<T> add(final Function<T, Collection<? super V>> c, final V... v) {
            c.apply(instance).addAll(Arrays.asList(v));
            return this;
        }

        public <V> CollectionBuilder<T, V> collectInto(final Function<T, Collection<? super V>> c) {
            return new CollectionBuilder<>(this, c);
        }

        public <V> CollectionBuilder2<T, V> collect(final Collection<V> c) {
            return new CollectionBuilder2<>(this, c);
        }

        public <V> CollectionBuilder2<T, V> collect(final Supplier<Collection<V>> c) {
            return collect(c.get());
        }

        public <V> CollectionBuilder2<T, V> collect() {
            return collect(new ArrayList<>());
        }

        public T instance() {
            return instance;
        }

    }

    static class CollectionBuilder<T, V> {

        private final Builder<T> builder;

        private final Function<T, Collection<? super V>> c;

        public CollectionBuilder(final Builder<T> builder, final Function<T, Collection<? super V>> c) {
            this.builder = builder;
            this.c = c;
        }

        public Builder<T> collect() {
            return builder;
        }

        public CollectionBuilder<T, V> add(final V value) {
            c.apply(builder.instance()).add(value);
            return this;
        }

    }

    static class CollectionBuilder2<T, V> {

        private final Builder<T> builder;

        private final Collection<V> c;

        public CollectionBuilder2(final Builder<T> builder, final Collection<V> c) {
            this.builder = builder;
            this.c = c;
        }

        public Builder<T> into(final Function<T, Collection<? super V>> finalCollector) {
            finalCollector.apply(builder.instance()).addAll(c);
            return builder;
        }

        public CollectionBuilder2<T, V> add(final V value) {
            c.add(value);
            return this;
        }

    }

    public static class Victim {

        private final Collection<String> strings = new ArrayList<>();

        private final Collection<Number> numbers = new ArrayList<>();

        Collection<String> getStrings() {
            return strings;
        }

        Collection<Number> getNumbers() {
            return numbers;
        }

        @Override
        public String toString() {
            return "Victim{" +
                "strings=" + strings +
                ", numbers=" + numbers +
                '}';
        }

    }

    public static void main(String[] args) {
        System.out.println("Functional Builder Demo");
        final JLabel jLabelInstance = of(new JLabel())
            .with(o -> o.setText("test"))
            .with(JLabel::setText, "test")
            .with(JLabel::setText, null)
            .with(JLabel::setDisabledIcon, of(new ImageIcon())
                .with(ImageIcon::setDescription, "icon description")
                .instance()
            )
            .instance();
        System.out.println(jLabelInstance);
        final ArrayList<JLabel> arrayListInstance = of(ArrayList<JLabel>::new)
            .with(List::add, new JLabel())
            .with(List::add, jLabelInstance)
            .instance();
        System.out.println(arrayListInstance);
        final Object instance = of(Victim::new)
            .add(Victim::getStrings, "asd")
            .add(Victim::getStrings, "asd", "def")
            .collectInto(Victim::getStrings)
            .add("qwe")
            .collect()
            .collect(ArrayList<String>::new)
            .add("poi")
            .into(Victim::getStrings)
            .<Integer>collect()
            .add(123)
            .into(Victim::getNumbers)
            .instance();
        System.out.println(instance);
    }

}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)