2014-11-19 4 views
1

저는 이것이 불가능하다고 99 % 확신합니다.하지만 시도해 볼만한 가치가 있다고 생각합니다. 템플릿을 구현하는 클래스를 만들 수 있습니까?Meta Generic in Java

동기 부여 : 일반적인 합성 클래스를 만들고 싶습니다.

예 :

f는 물론 인터페이스 T.에 정의 된 방법이다
public class GenericComposite<T> implements T { 
    List<T> m_items; 

    void add(T item) { 
     m_items.add(item); 
    } 

    @Override 
    void f() { 
     for (T item : m_items) { 
      item.f(); 
     } 
    } 
} 

우리가 거 ​​f를 할 것을 알고하지 않습니다() 우리가 그것을 전화도 우리가 그것을 할 위치 할 때. 이것이 가능하다는 것을 모르는 메타 메타 마술이 있습니까? 그렇지 않다면, 이것을 지원하는 다른 언어가 있습니까?

+0

자바에서는 T'는'class' 대'interface'입니다'알고하지 않을 것입니다. 다른 언어 옵션이 있는지 모릅니다. –

+1

'GenericComposite '이 템플릿이기 때문에 C++에서 이것을 할 수 있습니다 - 자바 제네릭과는 아주 다른 것입니다. – dasblinkenlight

답변

3

당신이 올바른지,이 자바 수 없습니다 : 컴파일러도 T는 확신 할 수없는 interface (A class 반대), 그래서 당신이 T을 구현 할 수 없습니다.

C++은 템플릿을 통해 이러한 가능성을 제공하지만 "일반 합성물"을 구현하는 데 도움이되지 않습니다. 문제는 f() 메쏘드 (또는 메쏘드가있는 실제 클래스의 메쏘드)입니다.

// This is not going to work! The syntax is not real. 
public class GenericComposite<T> implements T { 
    List<T> m_items; 

    void add(T item) { 
     m_items.add(item); 
    } 

    @Override 
    <all-methods-of-T>(); 
} 

@Override void f()을 쓰기 위해 당신이 Tvoid f()을 가지고 있음을 알고 있어야합니다 : 당신이 쓰고 싶었다 것은 이것이다. T의 모든 단일 메소드에 대해 알아야하며, 처음에는 T의 신원을 숨기는 목적을 상실합니다. GenericComposite<T>은 인터페이스, 즉 모든 메소드에 대해 알아야 할 모든 것을 알고 있습니다.

컴포지트를 빌드 할 때 하위 요소 목록을 사용하면 호출자가 리프 개체를 처리하는 것과 같은 방식으로 합성을 처리 할 수있는 메서드를 구현하는 것보다 훨씬 작은 문제가됩니다. 이러한 모든 "집계"메서드는 항상 사용자 지정이므로 합성의 일반적인 구조 구현은 거의 쓸모가 없습니다.

0

예 이렇게 할 수 있습니다.

public interface Thing { 
    void something(); 
} 

public Composite<T implements Thing> implements Thing { 
    private List<T> things = new ArrayList<>(); 

    @Override 
    public void something() { 
     for(Thing aThing:things) { 
      aThing.something(); 
     } 
    } 
} 

그러나 모든 것이 공통 인터페이스를 공유하고 있으므로이 문제를 해결하려면 제네릭이 정말로 필요합니까?

+3

OP의 질문과는 달리'T'는 무엇이든 할 수 있고'f()'는'T'의 한 방법입니다.'f()'를'물건 '에 넣는 것입니다.본질적으로,'Composite'는'T'가 아니라'Thing'을 구현합니다. – dasblinkenlight

+0

필자는 왜 이것이 내가 찾고있는 것이 아닌지를 쓰기 시작했다. 그러나 @dasblinkenlight는 내가하는 것보다 더 명확하게 설명했다. – wolfovercats

+0

''이라고 말해야한다. – Sebastian

1

예 Proxys 및 리플렉션을 사용하여 Java에서이 작업을 수행 할 수 있습니다. 나는 그것을 전에했다. 걱정해야 할 추가 문제는 값을 반환하는 메서드입니다. 여러 구현을 래핑하는 경우 반환 값은 실제로 반환합니까? 내 솔루션에서

, 나는 목록 또는 최종 결과 (모든 대표가 호출 어느 쪽이든) 여기

에서 첫 번째 결과를 반환하거나 클래스를 알려 열거를 사용하여 내 코드의

/** 
* {@code MultipleWrapper} uses dymanic proxies to wrap 
    * several instances of an interface. This allows 
* all wrapped instances to be called by only a single 
* call to the wrapper. 
* @author dkatzel 
*/ 
public final class MultipleWrapper<T> implements InvocationHandler{ 

private final ReturnPolicy policy; 
private final List<T> delegates = new ArrayList<T>(); 
/** 
* Since methods can only return a single 
* return value, only one of the wrapped 
* methods can be returned to the caller (even though 
* they will all be called). 
* @author dkatzel 
*/ 
public static enum ReturnPolicy{ 
    /** 
    * Return the first wrapped instance. 
    */ 
    RETURN_FIRST, 
    /** 
    * Return the last wrapped instance. 
    */ 
    RETURN_LAST 
} 
/** 
* Create a dynamic proxy to wrap the given delegate instances. 
* @param <T> the interface to proxy. 
* @param <I> the instances of T. 
* @param classType the class object of T. 
* @param policy the return policy to use on methods that return something. 
* @param delegates the list of delegates to wrap in the order in which 
* they will be called. 
* @return a new instance of T that wraps the delegates. 
* @throws IllegalArgumentException if no delegates are given 
* @throws NullPointerException if classType ==null or policy ==null or any delegate ==null. 
*/ 
@SuppressWarnings("unchecked") 
public static <T, I extends T> T createMultipleWrapper(Class<T> classType,ReturnPolicy policy, Iterable<I> delegates){ 

    return (T) Proxy.newProxyInstance(classType.getClassLoader(), new Class<?>[]{classType}, 
      new MultipleWrapper<T>(policy,delegates)); 
} 
/** 
* Convenience constructor which is the same as calling 
* {@link #createMultipleWrapper(Class, ReturnPolicy, Object...) 
* createMultipleWrapper(classType,ReturnPolicy.RETURN_FIRST,delegates)} 
* @see #createMultipleWrapper(Class, ReturnPolicy, Object...) 
*/ 
public static <T,I extends T> T createMultipleWrapper(Class<T> classType,Iterable<I> delegates){ 
    return createMultipleWrapper(classType,ReturnPolicy.RETURN_FIRST,delegates); 
} 
/** 
* Convenience constructor which is the same as calling 
* {@link #createMultipleWrapper(Class, ReturnPolicy, Object...) 
* createMultipleWrapper(classType,ReturnPolicy.RETURN_FIRST,delegates)} 
* @see #createMultipleWrapper(Class, ReturnPolicy, Object...) 
*/ 
@SafeVarargs 
public static <T,I extends T> T createMultipleWrapper(Class<T> classType,I... delegates){ 
    return createMultipleWrapper(classType,ReturnPolicy.RETURN_FIRST,Arrays.asList(delegates)); 
} 
/** 
* Convenience constructor which is the same as calling 
* {@link #createMultipleWrapper(Class, ReturnPolicy, Object...) 
* createMultipleWrapper(classType,ReturnPolicy.RETURN_FIRST,delegates)} 
* @see #createMultipleWrapper(Class, ReturnPolicy, Object...) 
*/ 
@SafeVarargs 
public static <T,I extends T> T createMultipleWrapper(Class<T> classType,ReturnPolicy policy,I... delegates){ 
    return createMultipleWrapper(classType,policy,Arrays.asList(delegates)); 
} 


private MultipleWrapper(ReturnPolicy policy,Iterable<? extends T> delegates){ 
    if(policy==null){ 
     throw new NullPointerException("policy can not be null"); 
    } 

    this.policy = policy; 
    for(T delegate : delegates){ 
     if(delegate ==null){ 
      throw new NullPointerException("delegate can not be null"); 
     } 
     this.delegates.add(delegate); 
    }  
    if(this.delegates.size()==0){ 
     throw new IllegalArgumentException("must wrap at least one delegate"); 
    } 
} 
@Override 
public Object invoke(Object proxy, Method method, Object[] args) 
     throws Throwable { 
    List<Object> returns = new ArrayList<Object>(delegates.size()); 
    try{ 
     for(T delegate :delegates){ 
      returns.add(method.invoke(delegate, args)); 
     } 
     if(policy == ReturnPolicy.RETURN_LAST){ 
      return returns.get(returns.size()-1); 
     } 
     return returns.get(0); 
    }catch(InvocationTargetException e){ 
     throw e.getCause(); 
    } 

} 

} 

그런 다음 같은 것을 할 수있는이 기능을 사용하려면

List<Type> listeners = ... 

Type wrappedListener = MultipleWrapper.createMultipleWrapper(Type.class, listeners);