如何在Java中包含多个方法?枚举不是正确的方法吗?

问题描述 投票:2回答:1

我有一个名为A的接口需要由程序启动后动态加载的类实现。让我们称之为B

此接口提供x(多于1个)方法。让我们从a()调用em到z()。现在我必须将这个类包装一段时间来测量和控制问题并在它自己的线程中运行它以便能够在需要太长时间时将其杀死。

因此,我发明了包装C的类B,因为Bdoes不能单独实现runnable。

下一部分是原始程序应该调用的类。新类DD实现接口A以隐藏模型中的整个控制部分。

现在我必须在D中包装接口的方法并将它们发送到C和C语言,然后将其解包并在对象B上执行它们。

这里有一些我想象的示例代码可以是:

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类中,明显的切换案例是使用该枚举将参数传递给类C中的正确方法,该类保存在类C als private字段中。

你有更好的解决方案吗?我个人不喜欢枚举的东西,如果参数太不同,这不会很好。

这样的事情是否有“标准”解决方案?

java concurrency enums wrapping
1个回答
9
投票

对此的标准解决方案是:为A使用“动态代理”(java.lang.reflect.Proxy)。这样可以节省几乎所有的样板代码。

此网站和Google包含足够的Proxy使用示例。

另外:我建议不要为每次调用使用新线程 - 如果被调用的方法很短,这是非常昂贵的。您可以使用Callable界面代替Runnable和线程池Executor。这也允许你在界面中有返回值:-)

编辑

为了好玩,我编写了动态代理和执行程序的东西。

给出以下接口A和示例实现B

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使用反射来调用任何java.lang.reflect.Method看起来像这样:

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创建一个新的Proxy时使用createProxyForMain类的其余部分用于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中完成。
  • 无需为每种方法编写任何代码。
© www.soinside.com 2019 - 2024. All rights reserved.