【问题标题】:A java method with both variable return type and variable input arguments具有可变返回类型和可变输入参数的 java 方法
【发布时间】:2015-01-28 09:52:09
【问题描述】:

我有一个抽象的 java 类“BaseOperation”。这个类只有一个抽象方法:

public abstract T execute()
{
    ...

    return T;
}

BaseOperation 的子类必须实现该方法:

public class GetUsersOperation extends BaseOperation<GetUsersResponse>
{
    ...

    @Override
    public GetUsersResponse execute()
    {

        ...

        return GetUsersResponse;
    }

}

这是将所有常见“操作”逻辑放入 BaseOperation 类的好方法,但每个具体子类的 execute() 方法仍具有不同的返回类型。

现在我需要更改此结构以允许 execute() 方法具有可变数量的参数。例如,一个具体的子类需要:

execute(String, int)

另一个需要:

execute(Date, Date, String)

这很棘手,因为执行方法是在基类中声明的。简单地重载基中的执行方法并不理想。首先,过载的数量将是巨大的。其次,每个子类只会使用其中一种执行方法,其他所有方法的意义何在?

(在我看来)最简单的解决方案是使用可变参数声明执行方法:

execute(Object... arguments)

然后向下转换子类中的所有参数:

execute(Object... arguments)
{
    String s = (String) arguments[0];
    ...
}

显然这有两个主要缺点:

  • 由于所有向下转换操作导致性能下降
  • 调用execute() 方法不再是严格类型化的,因​​为任何数量的对象都可以在没有编译器警告的情况下传递。

是否有没有这些缺点的模式或其他解决方案?

【问题讨论】:

    标签: java design-patterns


    【解决方案1】:

    如前所述,解决问题的常用方法是使用 bean 保存参数。但这里是另一种基于构建器方法的解决方案:

    public interface BaseOperation<T> {
       public T execute();
    }
    
    public class AddOperation implements BaseOperation<Integer> {
       private int a, b;
    
       public void setA(int arg){
         a = arg ;
         return this;
       }
    
       public void setB(int arg){
         b = arg;
         return this;
       }
    
       @Override
       public Integer execute() {
         return a+b ;
       }
    }
    

    然后像这样使用它:

    new AddOperation().setA(1).setB(2).execute();
    

    您可以通过这种方式混合必需和可选参数:

    public class MultipleAddOperation implements BaseOperation<Integer> {
      private int sum ;
    
      public MultipleAddOperation(int requiredInt){
        sum = requiredInt;
      }
    
      public void add(int optionalInt){
        sum += optionalInt ;
        return this;
      }
    
      @Override
      public Integer execute(){
        return sum;
      }
    }
    

    所以:

    new MultipleAddOperation(5).add(1).add(2).execute();
    

    【讨论】:

    • 我喜欢他如何将有关所需输入的逻辑编码为子类本身的属性(字段)(具有必要的设置方法),而不是作为单独的 bean 类。但是,没有什么可以阻止我在没有设置适当参数的情况下调用 execute()。这能解决吗?
    • @user1884155 是的,在操作构造函数中传递参数,请参阅我的编辑;)
    • 啊,很明显。我更喜欢这个解决方案而不是“简单”的 javabean 解决方案,因为我的所有参数都是必需的,而且我不想为我创建的每个操作类引入一个额外的 bean 类。谢谢!
    【解决方案2】:

    你可以使用一个持有参数的bean:

    public interface BaseOperation<T, U> {
        T execute(U input);
    }
    
    public class GetUsersOperation implements BaseOperation<GetUsersResponse, UserInput> {
    
        @Override
        public GetUsersResponse execute(UserInput input) {
            Date date = input.getDate();
            return new GetUsersResponse(date);
        }
    
    }
    

    您的抽象类只有一个抽象方法:最好使用接口。您可以实现多个接口,而只能扩展一个类。

    【讨论】:

    • 感谢您的及时回复。我的基类有其他方法,但它只有 1 个 PUBLIC 方法。所有其他私有/受保护的方法都不是抽象的,而是执行常见的工作,例如日志记录、解析消息等。接口在 java 1.7 中不能有实际代码,所以我认为将其转换为接口是不可能的。还是我在这个问题上错了?
    • @user1884155 不,你说得对,我以为它只有一个抽象方法。
    • 很好奇为什么人们更喜欢一个 bean 而不是一个具有多个构造函数的类?使用重载的构造函数,您可以避免设置参数的所有额外行,还可以提供一些可接受的参数组合和所需值的指示。
    • @Blegger 这很好,我现在可能会提出一种基于构造函数的方法。我想这就是为什么其他答案已被接受的原因(尽管我会使用构造函数来使字段最终化,而不是像提议的那样设置器)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-08
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 2021-09-21
    • 2020-11-16
    • 1970-01-01
    相关资源
    最近更新 更多