2012-11-03 54 views
2

我在java中有以下情況: 我有1個接口名爲「A」,需要由我在程序啓動後動態加載的類實現。讓我們稱它爲B. 這個接口提供了x(超過1)個方法。讓我們從()到z()調用em。 現在我必須將這個類包裝一段時間來測量和控制問題,並在自己的線程中運行它,以便能夠在需要太長時間時殺死它。 因此,我發明了包裝B的類C,因爲B本身並未實現可運行。 下一部分是原始程序應調用的類。新的D.D類實現接口A以及隱藏模型中的整個控制部分。 現在我必須在D中包裝接口的方法,並將它們發送給C,然後將它們解包並在對象B上執行它們。 我希望我解釋得很好。對不起,我的英語不好。在JAVA中包裝多個方法?枚舉不正確?

這裏誰我想象一些示例代碼也可以是:

public class D implements A { 

private C ai; 

public D(String aiName) { 
    ai = new C("trivialKi"); 
} 

private void call(parameters, ORIGIN_METHOD origin) { 
    AiTaskExecutor task = new AiTaskExecutor(parameters, origin, ai); 
    FutureTask<Long> tsk = new FutureTask<Long>(task); 

    Thread thread = new Thread(tsk); 
    thread.start(); 
    if (abort) { 
      tsk.cancel(true); 
    } 
} 

@Override 
public void a(g g, f f, t t) { 
    call(g, f, t, ORIGIN_METHOD.a); 
} 

@Override 
public void b(g g, t t, h h) { 
    call(g, t, h, ORIGIN_METHOD.b); 
} 

@Override 
public void c(g g, t t, f f) { 
    call(g, t, f, ORIGIN_METHOD.c); 
} 
} 

,並在類C中的明顯開關殼體與該枚舉的參數傳遞到在類保持在類B的正確的方法C als私人領域。

您是否有更好的解決方案? 我個人不喜歡枚舉的東西,如果參數太不同,這不工作得很好。 是否有這樣的標準解決方案?

+6

沒有枚舉,既不在您的描述中,也不在所提供的代碼中。我不明白你的問題。請嘗試給出最簡單的例子,並用吝嗇的名字,而不是A,B,C,D等 –

回答

9

對此的標準解決方案是:使用A的「動態代理」(java.lang.reflect.Proxy)。這可以節省您幾乎所有的樣板代碼。

本網站和Google包含足夠的使用示例Proxy

另外:我建議不要爲每個調用使用一個新的線程 - 如果被調用的方法很短,這是非常昂貴的。您可以使用Callable接口代替Runnable,而使用線程池Executor。這也可以讓你在你的界面的返回值:-)

編輯

只是爲了好玩我編寫動態代理和執行的事情。

鑑於以下接口A和樣品實施B:使用反射來調用任何java.lang.reflect.Method

interface A { 
    int a(int g, int f, int h); 
    int b(int x); 
} 

class B implements A { 
    @Override 
    public int a(int g, int f, int t) { 
     System.out.println("called a in thread "+Thread.currentThread().getName()); 
     return 42; 
    } 
    @Override 
    public int b(int x) { 
     System.out.println("called b in thread "+Thread.currentThread().getName()); 
     return 21; 
    } 
} 

一個適當Callable看起來像這樣:

class ReflectiveMethodCallable implements Callable<Object> { 
    private Object target; 
    private Method method; 
    private Object[] args; 

    public ReflectiveMethodCallable(Object target, Method method, Object[] args) { 
     this.target = target; 
     this.method = method; 
     this.args = args; 
    } 

    @Override 
    public Object call() throws Exception { 
     return method.invoke(target, args); 
    } 
} 

在其中創建這樣的ReflectiveMethodCallable的部分並給予ExecutorService的是InvocationHandlerjava.lang.reflect.Proxy

class MyInvocationHandler implements InvocationHandler { 
    private Object target; 
    private ExecutorService executorService; 

    public MyInvocationHandler(Object target, ExecutorService executorService) { 
     this.target = target; 
     this.executorService = executorService; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     try { 
      Callable<Object> task = new ReflectiveMethodCallable(target, method, args); 
      Future<Object> future = executorService.submit(task); 
      return future.get(); 
     } 
     catch(ExecutionException e1){ 
      try { 
       throw e1.getCause(); 
      } catch(InvocationTargetException e2){ 
       throw e2.getCause(); 
      } 
     } 
    } 
} 

InvocationHandler創造createProxyForProxy時使用。所述Main類的其餘部分被用於SSCCE例如:

public class Main { 
    public static void main(String[] args) throws InterruptedException { 
     ExecutorService executorService = Executors.newCachedThreadPool(); 

     // get B somehow 
     A a = new B(); 

     // get proxy for B 
     A proxy = createProxyFor(a, executorService); 

     // call proxy 
     System.out.println("current thread: "+Thread.currentThread().getName()); 

     int resultA = proxy.a(1,2,3); 
     System.out.println("calling a returned "+resultA); 

     int resultB = proxy.b(1); 
     System.out.println("calling b returned "+resultB); 

    } 

    static A createProxyFor(A a, ExecutorService executorService){ 
     InvocationHandler h = new MyInvocationHandler(a, executorService); 
     A proxy = (A)Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{A.class}, h); 
     return proxy; 
    } 
} 

輸出:

current thread: main 
called a in thread pool-1-thread-1 
calling a returned 42 
called b in thread pool-1-thread-1 
calling b returned 21 

要完成上:

  • A每一種方法將在另一個線程調用。
  • 線程被線程池重用。
  • 附加邏輯(例如時間測量,超時控制)可以在invokecall中完成。
  • 無需爲每種方法編寫任何代碼。
+0

多數民衆贊成多數民衆贊成在我正在尋找 非常感謝你的詳細解釋 – user1270045