另一个泛型 - 困惑的可怜的灵魂...如何在此代码中添加静态.start()方法?

时间:2013-01-31 00:01:25

标签: java generics

是的,仿制药是一个经常性的主题,在这里又一次......

目前,我有这段代码。 Processor是一个“简单”的通用界面。

public final class ProcessorChain<IN extends MessageProvider, OUT extends MessageProvider>
    implements Processor<IN, OUT>
{
    /**
     * The resulting processor
     */
    private final Processor<IN, OUT> p;

    /**
     * Start a processing chain with a single processor
     *
     * @param p the processor
     * @param <X> the input type
     * @param <Y> the output type
     * @return a single element processing chain
     */
    public static <X extends MessageProvider, Y extends MessageProvider>
        ProcessorChain<X, Y> startWith(final Processor<X, Y> p)
    {
        return new ProcessorChain<X, Y>(p);
    }

    /**
     * Private constructor
     *
     * @param p the processor
     */
    private ProcessorChain(final Processor<IN, OUT> p)
    {
        this.p = p;
    }

    /**
     * Add an existing processor to that chain
     *
     * <p>Note that this returns a <b>new</b> chain.</p>
     *
     * @param p2 the processor to add
     * @param <NEWOUT> the return type for that new processor
     * @return a new chain consisting of the previous chain with the new
     * processor appended
     */
    public <NEWOUT extends MessageProvider> ProcessorChain<IN, NEWOUT>
        chainWith(final Processor<OUT, NEWOUT> p2)
    {
        return new ProcessorChain<IN, NEWOUT>(merge(p, p2));
    }

    public Processor<IN, OUT> end()
    {
        return this;
    }

    @Override
    public OUT process(final ProcessingReport report, final IN input)
        throws ProcessingException
    {
        return p.process(report, input);
    }

    /**
     * Merge two processors
     *
     * @param p1 the first processor
     * @param p2 the second processor
     * @param <X> the input type of {@code p1}
     * @param <Y> the output type of {@code p1} and input type of {@code p2}
     * @param <Z> the output type of {@code p2}
     * @return a processor resulting of applying {@code p2} to the output of
     * {@code p1}
     */
    private static <X extends MessageProvider, Y extends MessageProvider, Z extends MessageProvider>
        Processor<X, Z> merge(final Processor<X, Y> p1, final Processor<Y, Z> p2)
    {
        return new Processor<X, Z>()
        {
            @Override
            public Z process(final ProcessingReport report, final X input)
                throws ProcessingException
            {
                return p2.process(report, p1.process(report, input));
            }
        };
    }
}

所以,目前,我可以写:

// p1 does <X, Y>, p2 does <Y, Z>, p3 does <Z, T>
Processor<X, T> p = ProcessingChain.startWith(p1).chainWith(p2).chainWith(p3).end();

它有效。事实上,我从未在仿制药方面走得那么远。

我想写的是:

Processor<X, T> p = ProcessingChain.start().add(p1).add(p2).add(p3).end();

我一直在努力做到这一点,但失败了。

我希望能够做到这一点的一个原因是,将来也可以写:

Processor<X, T> p = ProcessingChain.start().add(p1).stopOnError().etc().etc()

我觉得如果我知道如何.start(),那么“实用程序”处理器将不会成为问题。

那么,怎么做?

3 个答案:

答案 0 :(得分:2)

无法使用裸启动方法推断生成的ProcessorChain必须具有的类型。此外,正如@PaulBellora指出的那样,你勾勒出的start()方法本身不能是处理器,因为它没有足够的信息。

您可以使用单独的类作为start()方法的结果,尽管它不能是无参数的。 e.g:

public class ProcessorChainFactory<M extends MessageProvider> {

    public static <X extends MessageProvider> ProcessorChainFactory<X> start() {
        return null;
    }

    public static <X extends MessageProvider> ProcessorChainFactory<X> start(Class<X> clazz) {
        return null;
    }

    public <X extends MessageProvider> ProcessorChain<M, X> add(Processor<M, X> processor) {
        // TODO Auto-generated method stub
        return null;
    }        
}

然后可以通过几种方式调用:

    Processor<MessageProvider1, Final> processor = ...;

    ProcessorChain<MessageProvider1, Final> processor1 = ProcessorChainFactory.<MessageProvider1> start().add(processor);
    ProcessorChain<MessageProvider1, Final> processor2 = ProcessorChainFactory.start(MessageProvider1.class).add(processor);

我的感觉是,除了你当前的ProcessingChain.startWith(p1)之外,你没有得到更多,但也许它有用。

答案 1 :(得分:1)

无参数start方法应该返回什么?这是问题的症结所在,尽管你在问题中只提到了它。

请注意,您已将ProcessorChain声明为实施Processor - 因此ProcessorChain的任何实例都必须像一个实例一样。出于这个原因,创建一个没有ProcessorChain的{​​{1}}实例来包装是没有意义的。

一般来说,我会说构建器不应该实现它构建的接口,但是编写了我认为我至少有兴趣看到反驳的参数。

答案 2 :(得分:1)

嗯,好吧,有一种方法,虽然它有点hackish:

public static <X extends MessageProvider> ProcessorChain<X, X> start()
{
    final Processor<X, X> p = new Processor<X, X>()
    {
        @Override
        public X process(final ProcessingReport report, final X input)
            throws ProcessingException
        {
            return input;
        }
    };

    return new ProcessorChain<X, X>(p);
}

然而,它不会完全奏效。对于SValidationDataPp1执行<S, ValidationData>p2执行<ValidationData, P>,写作:

ProcessorChain.start().chainWith(p1).chainWith(p2).end()

导致此编译错误:

<NEWOUT>chainWith(Processor<MessageProvider,NEWOUT>) 
in ProcessorChain<MessageProvider,MessageProvider>
cannot be applied to
(Processor<S,ValidationData>)

上面的代码是我的第一次尝试......

但如果我写:

ProcessorChain.<S>start().chainWith(p1).chainWith(p2).end()

然后它有效!