【问题标题】:java callable with multiple methodsjava可调用多种方法
【发布时间】:2021-11-16 08:02:58
【问题描述】:

我正在尝试使用多种方法实现 java 可调用 而我的情况是这样的:

interface FsHandler {

  boolean existDirectory();
  boolean existFile(File);
  ...
}
interface FileHandler {

  void write(byte[]);
  void read(byte[]);
  ...
}

所有这些方法都由不同的存储后端实现,例如本地文件系统、aws s3 等

在寻找并行化此代码的方法时,我尝试使用 callable,但如果我理解正确,我需要在许多实现 callable 的小型抽象类中打破我的接口 - 每个方法一个,然后使用 callable,更不用说我仍然需要找到一种方法将调用添加到阻塞队列(使用执行器)

所以,我的疑问是:

  • 是否可以在已经存在/实现的方法上包装可调用对象?
  • 另一种思路是为每个需要实现可调用的方法创建一个抽象类,然后使用策略模式来决定使用哪个实现

例如:

interface WriteStrategy implements Callable<Void> {

  Void call();
  void write(byte[]);
  static WriteStrategy localFSStrategy(){...}
  static WriteStrategy S3Strategy() {...}

class FileHandler {
  private WriteStrategy strategy;

  public FileHandler(WriteStrategy strategy) {...}
  public void write(byte[]) { strategy.call(); }
}

我仍然不确定如何处理它:'(

【问题讨论】:

    标签: java design-patterns callable


    【解决方案1】:

    我不确定你在寻找什么,但如果你想包装一个可调用的方法,你可以将它包装在一个匿名类中,该类包括你想要包装的方法的对象,以及你想要包装的任何参数想传给它。给定:

    class A {
        int f1(final int i) {
            return i + i;
        }
    }
    

    看起来像这样:

    Callable<Integer> callAF1 = new Callable<>() {
        private A callA = a;
        private int aParam1 = 1;
    
        @Override
        public Integer call() {
            return callA.f1(aParam1);
        }
    };
    

    那时你可以用callAF1做任何你想做的事。

    【讨论】:

    • 嗨@John-Bayko,感谢您的帮助 :) 确实可行,但问题是我想避免每个方法都有一个可调用对象
    • Callables 是非常轻量级的对象,比闭包块/lambda 还小,所以我不用担心。
    【解决方案2】:

    您甚至不需要使用实现 Callable 声明任何类。

    相反,您可以使用对Callable 接口具有正确签名的方法引用或lambda 声明,并对返回类型进行适当的自动装箱。这允许一个类提供多个Callable 实现。

    以下是一些不同风格的示例:

    class Impl {
        public Impl() {};
    
        public void write(byte[] bytes) {
            throw new RuntimeException("not implemented yet");
        }
        public int doSomeOp() {
            return 0;
        }
        public byte[] read() {
            throw new RuntimeException("not implemented yet");
        }
    }
    public static void main(String[] args)
    {
        Impl impl = new Impl();
    
        byte[] ba = {65, 66, 67};
    
        // Method references with different return types
        Callable<Integer> callable1 = impl::doSomeOp;
        Callable<byte[]>  callable2 = impl::read;
    
        // lambda for void method, or methods needing extra arguments
        Callable<Void>    callable3 = () -> { impl.write(ba); return null; };
    
        // Then you can use with ExecutorService:
        ExecutorService  executor = Executors.newCachedThreadPool();
        Future<Integer> task1 = executor.submit(callable1);
        
        // You don't even need to declare the local variable "callable1"
        Future<Integer> task2 = executor.submit(impl::doSomeOp);
    }
    

    【讨论】:

    • 非常感谢@DuncG,我测试了你的建议,效果很好:)
    猜你喜欢
    • 2017-08-10
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 2011-09-23
    相关资源
    最近更新 更多