2011-11-18 6 views
1

A라는 "엔터티"(인터페이스)를 정의하는 응용 프로그램이 있고 AImpl이 함께 있다고 가정 해 보겠습니다. 그리고 클래스 A를 B, C, .. Z (BImpl, ...)로 확장 한 써드 파티 플러그인이 있으며 각각은 몇 가지 상태와 기능을 추가합니다. 또한 응용 프로그램에 A 인스턴스를 생성하는 "팩토리"가 있습니다.런타임시 여러 Java 클래스 *를 병합하는 방법 *?

내 "사용자"가 F, K 및 W와 같이 여러 개의 플러그 인을 동시에로드하여 해당 팩터 리를 생성하지 못하게하고 싶습니다. F, K 및 W와 동시에있을 "수퍼 A"인스턴스. "수퍼 A"가 F, K 및 W의 인터페이스를 구현하는 한 "인터페이스"및 "구현"이 엄격하게 구분되어 있다고 가정합니다 , 그것은 FImpl, KImpl 또는 WImpl이 아니라는 것을 명심해야합니다. 그래서 일종의 "런타임"다중 상속.

정확히 말해서 F, K 또는 W 소스 코드가 없으므로 타사 개발자는 각자 확장 기능에 대해 알 필요가 없습니다.

그래서 Java 클래스를 쉽게 병합 할 수있는 라이브러리가 있습니까? 이상적으로는 "충돌"을 관리하는 몇 가지 방법, 예를 들어 동일한 서명을 사용하는 개인 메서드를 정의하는 두 클래스 또는 동일한 기본 클래스 메서드를 재정의하려는 경우에 유용합니다.

참고 : 구성보다는 바이트 코드 조작을 사용하여 찾고 있습니다. 컴포지션은 기본 클래스의 재정의 메소드의 "확장"클래스를 방지하고 더 많은 메모리를 사용합니다.

[편집] @Gray에 대한 내 의견에 설명했듯이 컴포지션은 여러 가지 이유로 좋은 해결책이 아닙니다. 당신이 그것을 할 수있는 동안, 당신이 제대로한다면, 아주 작은 클래스들과 인터페이스들, 그리고 그것들을 하나의 단일 객체처럼 보이게하는 다량의 글루 코드로 마무리하게됩니다. 이는 또한 생산성 저하로 이어지는 큰 코딩 오버 헤드 외에도 응용 프로그램이 훨씬 많은 메모리를 사용하며 모든 방향의 추가 된 우회로 인해 훨씬 ​​더 느려지는 효과도 있습니다.

작고 짧은 DB 트랜잭션을 처리하는 응용 프로그램의 경우 컴포지션이 완벽 할 수 있지만 항상 RAM에 기가 바이트의 핫 데이터를 유지해야하는 응용 프로그램의 경우에는 이것이 수행됩니다. 실제 비용, 개발 시간 및 클라이언트 및 서버에 대한 메모리 및 CPU 요구 사항.

확장 할 수있는 기본 클래스의 메서드에 대한 제한이있는 "자연스럽게"(인터페이스 우선 스타일의 프로그래밍 IS입니다) 코드를 작성할 수있는 솔루션은보다 "저렴합니다" 구성.

+0

정확히 무엇인지 찾고 싶지만 [Decorator Pattern] (http://en.wikipedia.org/wiki/Decorator_pattern)이 도움이 될 수 있습니다. – jpm

+1

어떻게 갈등을 해결할 계획입니까? –

+0

@Dave Newton Strategy-Pattern과 Design-For-Extension이 혼합되어 충돌을 줄이거 나 없애는 데 도움이됩니다. 좋은 점은 특정 충돌이 자동으로 관리 될 수 있다는 것입니다. 예제는 객체/값의 "집합"을 반환하는 메서드 (순서가 지정된 목록이 아님), "전체", "필터"메서드 및 기타 메서드를 반환하는 메서드입니다. 갈등을 관리하는 것이 가장 복잡한 부분입니다. 그래서 나는 나를 위해 그것을하는 라이브러리를 찾고 싶었습니다. –

답변

0

당신이 생각하거나 소리내는 것만큼이나 사소한 것은 아닙니다. 그러나 예,이 "플러그인 기반 아키텍처"를위한 프레임 워크가 있습니다. 요즘 인기있는 것 중 하나는 다음과 같습니다. http://www.osgi.org/Main/HomePage

+0

나는 그것이 사소한 생각은하지 않았다. 만약 내가 가지고 있었다면, 나는 방금 프로그래밍에 착수했을 것이다! 어려운 부분은 갈등을 관리하는 것이라고 생각합니다. 누군가가 충돌 해결을위한 사전 정의 된 전략을 포함하는 라이브러리를 만들었 으면합니다. –

+0

OSGi가 나의 첫 번째 접근 방식 이었지만 OSGi는 거친 재사용 접근 방식입니다. 실제로 클래스를 확장하지는 않지만 싱글 톤 (singleton)과 같은 서비스를 함께 붙입니다. 내가 필요한 것은 대량의 엔티티를 RAM에 저장하는 것이지만, 그 엔티티의 상태와 동작은 플러그인에 의해 확장 될 수 있습니다. 이것은 OSGi 방식과 잘 맞지 않습니다. –

1

모든 F, K 및 W 플러그인이 삽입 된 프록시 개체로 수행 할 수 있습니다. 질문이 암시하는 것처럼 인터페이스 인 경우 이렇게하는 것이 더 쉽습니다. 그렇지 않다면 당신은 cglib처럼 더 많은 마법을 쓸 것입니다. 여기에 프록시 문서 : 당신은 방법의지도를 만들 수

public class MyProxy implements InvocationHandler { 
    private F f; private K k; private W w; 

    public static Object newInstance(F f, K k, W w) { 
     return java.lang.reflect.Proxy.newProxyInstance(
      obj.getClass().getClassLoader(), 
      new Class[] { F.class, K.class, W.class ], 
      new MyProxy(f, k, w)); 
    } 

    private MyProxy(F f, K k, W w) { 
     this.f = f; this.k = k; this.w = w; 
    } 

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable{ 
     try { 
      // pseudo code starts here 
      if (f has method that matches m.getName() and args) { 
       find method from f 
       return fMethod.invoke(obj, args); 
      } else (same thing for f and w ...) {} 
      throw some exception about missing method 
     } catch (InvocationTargetException e) { 
      throw e.getTargetException(); 
     } catch (Exception e) { 
      throw new RuntimeException("unexpected invocation exception", e); 
     } 
    } 
} 

당신이 원하는 경우에 밖으로 호출 할 때마다 그림을 위해 :

다음

http://download.oracle.com/javase/1.5.0/docs/guide/reflection/proxy.html

이 예에서 조정 된 코드 샘플입니다 일부 플러그인에서 메소드 호출. @DaveNewton은 그 중 두 명이 동일한 인수를 사용하여 동일한 메소드 이름을 갖는 경우 그 트릭이 무엇인지 맞습니다.

+0

당신의 접근 방식은 단순한 경우에 그것을 할 수 있지만, 그것은 제가 작곡으로 설명하는 것입니다. 컴포지션의 주된 문제 중 하나는 기본 클래스 AImpl에 "상태"가있는 경우 해당 상태가 플러그인에 의해 정의 된 모든 인스턴스에 복제되어 확장된다는 것입니다. 이것은 단지 작동하지 않습니다. 플러그인이 실제로 AImpl을 확장하지 않고 자신이 정의한 새로운 상태와 동작을 포함하는 경우 다른 플러그인을 만들면 첫 번째 문제 만 해결됩니다. 이제 FImpl, KImpl 및 WImpl은 A 인터페이스를 더 이상 구현할 수 없으며 AImpl 객체에 액세스 할 수있는 방법이 필요합니다. 그래서 그것은 오히려 추악해진다. –

2

는 사용하기 쉬운 라이브러리 아니지만, 내가 지금까지 발견 된 가장 가까운 ASM에 그것을 할이 "레시피"입니다 :

Merging class methods with ASM

그러나 페이지가 말한대로, 그렇지 않습니다 코너 케이스를 처리하십시오. 따라서 라이브러리를 사용하는 것이 더 쉬울 것입니다.

관련 문제