首页 > 解决方案 > 可变/不可变方法的命名约定

问题描述

当您有两个通用名称方法执行相同的操作,而一个是不可变的而另一个是可变的时,命名约定是什么?

例子

考虑接受 2 个数字数组的单元格操作:不可变版本创建一个新数组来放入结果,而可变版本将结果存储在第一个数组参数中。

由于方法名称是通用的,例如apply操作策略 (add, sub, mul, div) 由第三个参数指定,因此您不能使用诸如add可变性 (a = a + 1) 和plus不变性 (c = a +乙)。

代码(将被跳过)

以下细节可能是题外话,但为了说明我在谈论什么方法:

@FunctionalInterface 
public interface BinaryOperation { double apply(double a, double b); }

public final class BinaryOperations {
    private BinaryOperations() {}

    public static final BinaryOperation ADD = (a, b) -> a + b;
    public static final BinaryOperation SUB = (a, b) -> a - b;
    public static final BinaryOperation MUL = (a, b) -> a * b;
    public static final BinaryOperation DIV = (a, b) -> a / b;
}

public final class DoubleArraysMath {
    private DoubleArrayMath() {}

    // ---> METHOD NAME OF INTEREST
    public static void applyAsMutable(double[] a, double[] b, BinaryOperation o) {
        apply(a, a, b, o);
    }
    // ---> METHOD NAME OF INTEREST
    public static double[] applyAsImmutable(double[] a, double[] b, BinaryOperation o) {
        double[] c = new double[a.length];
        return apply(c, a, b, o);
        return c;
    }
    private static void apply(double[] result, double[] a, double[] b, BinaryOperation o) {
        for (int i = 0; i < a.length; i++) { result[i] = o.apply(a[i], b[i]); }
    }
}

// just an example of usage
double[] r = DoubleArraysMath.applyAsImmutable(a, b, BinaryOperations.MUL);
DoubleArraysMath.applyAsMutable(a, b, BinaryOperations.ADD);
DoubleArraysMath.applyAsMutable(a, b, (ai, bi) -> ai*ai + bi); // some custom operation

单独的课程

在类中分离可变和不可变方法DoubleArraysMutableMath可以避免DoubleArraysImmutableMath在每个方法名称的开头/结尾写入“可变/不可变”前缀/后缀。遵循这种模式,您最终将得到任何名为“可变/不可变”的实用程序类(无论它是否好,我都会留下一个悬而未决的问题)。

单类问题

如果我们想在单个类中使用这些方法(更好的维护),正确的命名“模式”是什么?我在代码示例中使用的模式“asMutable/asImmutable”或通常的“可变/不可变”可能与较长的方法名称不兼容。还有其他选择吗?

标签: language-agnosticnaming-conventionsimmutability

解决方案


根据评论编辑

您绝对应该分别实现可变和不可变类。方法名称可以相似也可以不同,这并不重要,因为接口会有所不同。

单班

可变性策略可以作为方法的附加参数提及,例如:

apply(a,b,Operation.ADD, ResultValue.NEW)
apply(a,b,Operation.ADD, ResultValue.FIRST_ARG)
apply(a,b,Operation.ADD, ResultValue.SECOND_ARG)

但是,在单个方法中使用多种策略会使该方法使客户感到困惑并且容易出错。

如果方法的签名是

double [] apply(double[] arg1, double[] arg2, BinaryOperation)

那么可变性或不变性可以是 BinaryOperation 本身的一部分:

public class FirstArgMutablePlusOperation {
    double[] apply(double[] arg1, double[] arg2) {
         //sample mutation
         arg1[0] = arg1[0] + arg2[0];
         // still return arg1 as a result
         return arg1;
    }
}

public class SecondArgMutablePlusOperation {
    double[] apply(double[] arg1, double[] arg2) {
         //sample mutation
         arg2[0] = arg1[0] + arg2[0];
         // still return arg2 as a result
         return arg2;
    }
}

public class ImmutablePlusOperation {
    double[] apply(double[] arg1, double[] arg2) {
         //sample mutation
         double[] result = new double[arg1.length];
         result[0] = arg1[0] + arg2[0];
         return result;
    }
}

然后用户可以使用正确的策略调用 apply 方法:

apply(arg1, arg2, new FirstArgMutablePlusOperation());
apply(arg1, arg2, new SecondArgMutablePlusOperation());
double[] result = apply(arg1, arg2, new ImmutablePlusOperation());

不可变/可变策略可以是 BinaryOperation 的一部分。但是,我宁愿避免这种解决方案,因为它会引入 if 语句和庞大的实现:

public enum ResultStrategy 
{ RESULT, FIRST_ARG, SECOND_ARG };

public class PlusOperation extends BinaryOperation {
        private final ResultStrategy strategy;
        public PlusOperation(final ResultStrategy strategy) {
              this.strategy = strategy
        }
        double[] apply(double[] arg1, double[] arg2) {
             if(strategy == ResultStrategy.FIRST_ARG) {
                  //sample mutation
                  arg1[0] = arg1[0] + arg2[0];
                  // still return arg1 as a result
                  return arg1;
             } else if(strategy == ResultStrategy.SECOND_ARG) {
                  //sample mutation
                  arg2[0] = arg1[0] + arg2[0];
                  // still return arg2 as a result
                  return arg2;
             } else if(strategy == ResultStrategy.RESULT) {
                  double[] result = new double[arg1.length];
                  result[0] = arg1[0] + arg2[0];
                  return result;
             }
        }
    }

用法:

apply(arg1, arg2, new PlusOperation(ResultStrategy.FIRST_ARG));
apply(arg1, arg2, new PlusOperation(ResultStrategy.SECOND_ARG));
double[] result = apply(arg1, arg2, new PlusOperation(ResultStrategy.RESULT));

更新

根据有问题提供的示例代码

public enum ResultStrategy { FIRST_ARG, NEW_RESULT;} // SECOND_ARG = apply(b, a)

public class DoubleArraysMath {
    ...
    public static double[] apply(ResultStrategy rs, double[] a, double[] b, BinaryOperation o) {
        if (rs == ResultStrategy.FIRST_ARG) { return apply(a, a, b, o); }
        return apply(new double[a.length], a, b, o);
    }
}

推荐阅读