Developing an RxJava Base Class/Factory Class for Common RxJava Stages

Viewed 154

I am investigating the use of RxJava/Retrofit within my current Android Application.

My Android application has to support many RestFul Web Service calls to maintain both User and reference data.

Although I call many different API's, at a high level they can be grouped into a small set of Call "patterns".

For example all my API calls employ the same Completable InitialProcess, RetryProcess and ErrorProcess.

What I would like to do is create a Base Class, (Step) Builder, and/or Factory solution that allows me to provide just the unique RxJava stages and have them combined with the "Common" stages mentioned above.

The solution will allow me to specify subscribeOn()/observeOn() as well as allowing me the choice of blockingWait() or subscribe() etc.

For example say that I need the following operation sequence:-

  commonInitialProcess()
                .andThen(Completable.defer(() -> uniqueCompletableProcessX()))
                .andThen(Single.defer(() -> uniqueSingleProcessA())))
                .doOnSuccess(commonSuccessProcess())
                .ignoreElement()
                .andThen(Single.defer(() -> uniqueSingleProcessB())))
                .doOnSuccess(commonSuccessProcess())
                .ignoreElement()
                .andThen(uniqueCompletableProcessY())
                .retryWhen(commonRetryWhenProcess())
                .doOnComplete(uniqueCompleteProcess())
                .doOnError(commonErrorProcess())
                .blockingAwait();

I would supply

uniqueCompletableProcessX()
uniqueSingleProcessA()
uniqueSingleProcessB()
uniqueCompletableProcessY()
uniqueCompleteProcess()

And receive back the complete sequence shown above, which I can then execute with blockingAwait().

In another example

 commonInitialProcess()
                .andThen(Completable.defer(() -> uniqueCompletableProcessZ()))
                .andThen(Single.defer(() -> uniqueSingleProcessC())))
                .doOnSuccess(commonSuccessProcess())
                .retryWhen(commonRetryWhenProcess())
                .doOnComplete(uniqueCompleteProcessZ())
                .doOnError(commonErrorProcess())
                .subscribe();

I would supply

uniqueCompletableProcessZ()
uniqueSingleProcessC()
uniqueCompleteProcessZ()

And receive back the complete sequence shown above, which I can then execute with subscribe().

I've tried developing a Step Builder to support the High Level types

This is mode Step builder

public class FigurateSequence extends Sequence {

    private static final int COMMON_INITIAL_PROCESS = 0;
    private static final int UNIQUE_COMPLETABLE_STEP_A = 1;

    private static final int UNIQUE_SINGLE_STEP_B = 0;

    public FigurateSequence(final FigurateSequenceBuilder figurateSequenceBuilder) {
        COMPLETABLES.addAll(figurateSequenceBuilder.getCompletables());
        SINGLES.addAll(figurateSequenceBuilder.getSingles());
    }

    public static Step_0001 builder() {
        return new FigurateSequenceBuilder();
    }

    public interface Step_0001 {
        Step_0002 first(final Completable completable);
    }

    public interface Step_0002 {
        Build second(final Single<String> single);
    }

    public interface Build {
        FigurateSequence build();
    }

    public static class FigurateSequenceBuilder implements Step_0001, Step_0002, Build {

        private final List<Completable> completables = new LinkedList<>();
        private final List<Single<String>> singles = new LinkedList<>();

        /**
         * 
         */
        private FigurateSequenceBuilder() {

        }

        @Override
        public Step_0002 first(final Completable completable) {
            completables.add(completable);
            return this;
        }

        @Override
        public Build second(final Single<String> single) {
            singles.add(single);
            return this;
        }

        @Override
        public FigurateSequence build() {
            return new FigurateSequence(this);
        }

        /**
         * @return the completables
         */
        public List<Completable> getCompletables() {
            return completables;
        }

        /**
         * @return the singles
         */
        public List<Single<String>> getSingles() {
            return singles;
        }
    }

    public void execute() {

        COMPLETABLES.get(COMMON_INITIAL_PROCESS)
        .andThen(Completable.defer(() -> COMPLETABLES.get(UNIQUE_COMPLETABLE_STEP_A)))
        .andThen(Single.defer(() -> SINGLES.get(UNIQUE_SINGLE_STEP_B)))
        .subscribe();       
    }
}

and Base Sequence Class

public class Sequence {

    protected final List<Completable> COMPLETABLES = new LinkedList<>();
    protected final List<Single<String>> SINGLES = new LinkedList<>();

    public Sequence() {
        COMPLETABLES.clear();
        SINGLES.clear();

        COMPLETABLES.add(getCommonInitialProcess());
    }


    /**
     * @return
     * 
     */
    private Completable getCommonInitialProcess() {
        return Completable.create(new CompletableOnSubscribe() {

            @Override
            public void subscribe(final CompletableEmitter emitter) throws Exception {
                Thread.sleep(500);
                System.out.println("CommonInitialProcess()");
                emitter.onComplete();
            }
        });

    }

}

Which works, however its use is still "clunky"

FigurateSequence.builder().first(getUniqueCompletableProcess_A()).second(getUniqueSingleProcess_A()).build().execute();

However there are some cases that are still troublesome

Such as when I have both a default and custom "Step Sequences".

for example if I have a default DoOnError() and a custom DoOnError() how do I define my step builders inner interfaces to cope with an "optional" step?

0 Answers
Related