简体   繁体   English

寻找合适的设计模式

[英]Looking for appropriate design pattern

Our code has several processors, each one having several api methods, where each method is overloaded also with same method that can accept collection. 我们的代码有几个处理器,每个处理器都有几个api方法,其中每个方法也被可以接受收集的相同方法重载。
For example: 例如:

public class Foo {
    public X foo(Y y){...}
    public Collection<X> foo(Collection<Y> y){... // iterate and execute foo(y) ... }
    public Z bar(W w){...}
    public Collection<Z> bar(Collection<W> w){... // iterate and execute bar(w) ... }
}
public class Other{
    // also method and method on collection
}

Naturally, those methods on collections are actually duplication code of iteration. 自然,集合上的那些方法实际上是迭代的重复代码。
What we are looking for, is kind of way to make some pattern or use generics, so the iteration over collection will be implemented once , also for that need a way to somehow pass the method name. 我们正在寻找的是一种制作某种模式或使用泛型的方法,因此遍历集合迭代将被实现一次 ,同样,这也需要一种以某种方式传递方法名称的方法。

I'd suggest Startegy pattern . 我建议使用Startegy模式 And do something like: 并执行类似的操作:

public interface Transformer<X, Y> {
    Y transform( X input );
}

class Processor {

    public <X,Y> Collection<Y> process( Collection<X> input, Transformer<X, Y> transformer) {
        Collection<Y> ret = new LinkedList<Y>();
        // generic loop, delegating transformation to specific transformer
        for( X x : input) {
            ret.add( transformer.transform( x ) );
        }
        return ret;
    }
}

Example: 例:

public static void main( String[] args ) {
        List<String> strings = new LinkedList<String>();
        strings.add( "1" );
        strings.add( "2" );
        strings.add( "3" );

        Processor p = new Processor();

        Collection<Integer> numbers = p.process( strings, new Transformer<String, Integer>() {
            @Override
            public Integer transform( String input ) {
                return Integer.parseInt( input );
            }
        } );
    }

I can't see how reflection could help here. 我看不到反射在这里有什么帮助。 You're trying to replace something as trivial as 您正在尝试替换一些琐碎的事情

public Collection<X> foo(Collection<Y> y) {
    List<X> result = Lists.newArrayList();
    for (Y e : y) result.add(foo(e));
    return result;
}

by something probably much slower. 速度可能要慢得多。 I don't think that saving those 3 lines (several times) is worth it, but you might want to try either annotation processing (possibly without using annotations) or dynamic code generation. 我认为保存这三行(几次)并不值得,但是您可能想要尝试注释处理(可能不使用注释)或动态代码生成。 In both cases you'd write the original class as is without the collection methods and use a different one containing both the scalar and the collection methods. 在这两种情况下,您都将按原样编写原始类而不使用收集方法,而使用包含标量和收集方法的另一类。


Or you might want to make it more functionally styled: 或者,您可能希望使其更具功能性:

public class Foo {
    public final RichFunction<Y, X> foo = new RichFunction<Y, X>() {
        X apply(Y y) {
            return foo(y);
        }
    }

    // after some refactoring the original method can be made private
    // or inlined into the RichFunction
    public X foo(Y y){...}

    // instead of calling the original method like
    // foo.foo(y)
    // you'd use
    // foo.foo.apply(y)
    // which would work for both the scalar and collection methods
}

public abstract class RichFunction<K, V> extends com.google.common.base.Function<K, V> {
    Collection<V> apply(Collection<K> keys) {
        List<V> result = Lists.newArrayList();
        for (K k : keys) result.add(apply(k));
        return result;
    }
}

RUAKH - I chosed to implement your suggestion for reflection (although, admit, I don't like reflection). RUAKH-我选择实施您对反思的建议(尽管,承认,我不喜欢反思)。 So, I did something like the code below THANKS :) 所以,我做了一些类似下面的代码:)

public class Resource {
    private static final int CLIENT_CODE_STACK_INDEX;
    static {
        // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
        int i = 0;
        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
            i++;
            if (ste.getClassName().equals(Resource.class.getName())) {
                break;
            }
        }
        CLIENT_CODE_STACK_INDEX = i;
    }
    public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName();
    }
    protected <IN,OUT> Collection<OUT> doMultiple(String methodName, Collection<IN> inCol, Class<?>... parameterTypes){
        Collection<OUT> result = new ArrayList<OUT>();
        try {
            Method m = this.getClass().getDeclaredMethod(methodName, parameterTypes);
            if (inCol==null || inCol.size()==0){
                return result;
            }
            for (IN in : inCol){
                Object o = m.invoke(this, in);
                result.add((OUT) o);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}

public class FirstResource extends Resource{
    public String doSomeThing(Integer i){
        // LOTS OF LOGIC
        return i.toString();
    }
    public Collection<String> doSomeThing(Collection<Integer> ints){
        return doMultiple(getCurrentMethodName(), ints, Integer.class);
    }
}

You should use Strategy pattern. 您应该使用策略模式。 By using Strategy pattern you can omit the usage if/else which makes the code more complex. 通过使用策略模式,您可以省略if / else用法,这会使代码更加复杂。 Where strategy pattern creates less coupled code which is much simpler. 在其中策略模式创建耦合代码更少的情况下,这要简单得多。 By using Strategy pattern you can achieve more ways to configure code dynamically. 通过使用策略模式,您可以实现更多方式来动态配置代码。 So I would like to suggest you to use Strategy pattern. 因此,我建议您使用策略模式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM