为内部子接口创建"默认构造函数"

Fra*_*kyi 3 java constructor default interface java-8

好吧,标题可能很难理解.我找不到正确的东西.所以,基本上我使用Java 8函数来创建可重试的API.我想要一个简单的接口实现,所以我在of(...)Retryable接口的每个实现中创建了一个方法,我们可以使用lambda表达式,而不是手动创建一个匿名类.

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public interface Retryable<T, R> extends Function<T, R>{

    void retrying(Exception e);

    void skipping(Exception e);

    int trials();

    @Override
    default R apply(T t) {
        int trial = 0;
        while (true) {
            trial++;
            try {
                return action(t);
            } catch (Exception e) {
                if (trial < trials()) {
                    retrying(e);
                } else {
                    skipping(e);
                    return null;
                }
            }
        }
    }

    R action(T input) throws Exception;

    interface RunnableRetryable extends Retryable<Void, Void> {

        static RunnableRetryable of(Consumer<Exception> retrying, Consumer<Exception> skipping, int trials, CheckedRunnable runnable) {
            return new RunnableRetryable() {
                @Override
                public void retrying(Exception e) {
                    retrying.accept(e);
                }

                @Override
                public void skipping(Exception e) {
                    skipping.accept(e);
                }

                @Override
                public int trials() {
                    return trials;
                }

                @Override
                public Void action(Void v) throws Exception {
                    runnable.tryRun();
                    return null;
                }
            };
        }

        @FunctionalInterface
        interface CheckedRunnable extends Runnable {

            void tryRun() throws Exception;

            @Override
            default void run() {
                try {
                    tryRun();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    interface ConsumerRetryable<T> extends Retryable<T, Void> {

        static <T> ConsumerRetryable of(Consumer<Exception> retrying, Consumer<Exception> skipping, int trials, CheckedConsumer<T> consumer) {
            return new ConsumerRetryable<T>() {
                @Override
                public void retrying(Exception e) {
                    retrying.accept(e);
                }

                @Override
                public void skipping(Exception e) {
                    skipping.accept(e);
                }

                @Override
                public int trials() {
                    return trials;
                }

                @Override
                public Void action(T t) throws Exception {
                    consumer.tryAccept(t);
                    return null;
                }
            };
        }

        @FunctionalInterface
        interface CheckedConsumer<T> extends Consumer<T> {

            void tryAccept(T t) throws Exception;

            @Override
            default void accept(T t) {
                try {
                    tryAccept(t);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    interface SupplierRetryable<T> extends Retryable<Void, T> {

        static <T> SupplierRetryable of(Consumer<Exception> retrying, Consumer<Exception> skipping, int trials, CheckedSupplier<T> supplier) {
            return new SupplierRetryable<T>() {
                @Override
                public void retrying(Exception e) {
                    retrying.accept(e);
                }

                @Override
                public void skipping(Exception e) {
                    skipping.accept(e);
                }

                @Override
                public int trials() {
                    return trials;
                }

                @Override
                public T action(Void v) throws Exception {
                    return supplier.tryGet();
                }
            };
        }

        @FunctionalInterface
        interface CheckedSupplier<T> extends Supplier<T> {

            T tryGet() throws Exception;

            @Override
            default T get() {
                try {
                    return tryGet();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    interface FunctionRetryable<T, R> extends Retryable<T, R> {

        static <T, R> FunctionRetryable of(Consumer<Exception> retrying, Consumer<Exception> skipping, int trials, CheckedFunction<T, R> function) {
            return new FunctionRetryable<T, R>() {
                @Override
                public void retrying(Exception e) {
                    retrying.accept(e);
                }

                @Override
                public void skipping(Exception e) {
                    skipping.accept(e);
                }

                @Override
                public int trials() {
                    return trials;
                }

                @Override
                public R action(T t) throws Exception {
                    return function.tryApply(t);
                }
            };
        }

        @FunctionalInterface
        interface CheckedFunction<T, R> extends Function<T, R> {

            R tryApply(T t) throws Exception;

            @Override
            default R apply(T t) {
                try {
                    return tryApply(t);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,每种of(...)方法都有很多重复的代码.我可以创造出一种"构造"的(这是不正确的单词,因为接口不能有构造函数)在可重试界面,但我不知道怎么办.有人有想法吗?

Hol*_*ger 5

主要问题是你的API爆炸.扩展的所有这些嵌套接口Retryable都不会添加任何功能,但是一旦它们成为API的一部分,就需要此代码的用户处理它们.此外,它们是此代码重复的原因,因为这些冗余接口中的每一个都需要其自己的实现,而所有实现基本上都是相同的.

删除这些过时类型后,您可以简单地将操作实现为委托:

public interface Retryable<T, R> extends Function<T, R>{
    void retrying(Exception e);
    void skipping(Exception e);
    int trials();
    @Override default R apply(T t) {
        try { return action(t); }
        catch(Exception e) {
            for(int trial = 1; trial < trials(); trial++) {
                retrying(e);
                try { return action(t); } catch (Exception next) { e=next; }
            }
            skipping(e);
            return null;
        }
    }

    R action(T input) throws Exception;

    public static Retryable<Void, Void> of(Consumer<Exception> retrying,
            Consumer<Exception> skipping, int trials, CheckedRunnable runnable) {
        return of(retrying, skipping, trials, x -> { runnable.tryRun(); return null; });
    }

    @FunctionalInterface interface CheckedRunnable extends Runnable {
        void tryRun() throws Exception;
        @Override default void run() {
            try { tryRun(); } catch (Exception e) { throw new RuntimeException(e); }
        }
    }

    public static <T> Retryable<T, Void> of(Consumer<Exception> retrying,
            Consumer<Exception> skipping, int trials, CheckedConsumer<T> consumer) {
        return of(retrying, skipping, trials,
                  value -> { consumer.tryAccept(value); return null; });
    }

    @FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
        void tryAccept(T t) throws Exception;
        @Override default void accept(T t) {
            try { tryAccept(t); } catch (Exception e) { throw new RuntimeException(e); }
        }
    }

    public static <T> Retryable<Void, T> of(Consumer<Exception> retrying,
            Consumer<Exception> skipping, int trials, CheckedSupplier<T> supplier) {
        return of(retrying, skipping, trials, voidArg -> { return supplier.tryGet(); });
    }

    @FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
        T tryGet() throws Exception;
        @Override default T get() {
            try { return tryGet(); }
            catch (Exception e) { throw new RuntimeException(e); }
        }
    }

    public static <T, R> Retryable<T, R> of(Consumer<Exception> retrying,
            Consumer<Exception> skipping, int trials, CheckedFunction<T, R> function) {
        return new Retryable<T, R>() {
            @Override public void retrying(Exception e) { retrying.accept(e); }
            @Override public void skipping(Exception e) { skipping.accept(e); }
            @Override public int trials() { return trials; }
            @Override public R action(T t) throws Exception {
                return function.tryApply(t);
            }
        };
    }

    @FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
        R tryApply(T t) throws Exception;
        @Override default R apply(T t) {
            try { return tryApply(t); }
            catch (Exception e) { throw new RuntimeException(e); }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

只需要一个实现类,它必须能够处理一个参数和一个返回值,其他的可以简单地使用适配器函数委托给它,执行任一操作,删除参数或返回null,或两者兼而有之.

对于大多数用例,lambda表达式的形状适合选择正确的方法,例如

Retryable<Void,Void> r = Retryable.of(e -> {}, e -> {}, 3, () -> {});
Retryable<Void,String> s = Retryable.of(e -> {}, e -> {}, 3, () -> "foo");
Retryable<Integer,Integer> f = Retryable.of(e -> {}, e -> {}, 3, i -> i/0);
Run Code Online (Sandbox Code Playgroud)

但有时需要一点提示:

// braces required to disambiguate between Function and Consumer
Retryable<String,Void> c = Retryable.of(e->{}, e ->{}, 3,
                                        str -> { System.out.println(str); });
Run Code Online (Sandbox Code Playgroud)