我有一个接口Value实现的层次结构,将大大简化它。假设我有两个实现,NumberValue和StringValue。

有一个平均操作仅对带有签名的NumberValue有意义

NumberValue平均值(NumberValue numberValue){
...
}

在创建了这样的变量并在各种集合中使用它们之后的某个时候,我需要平均一个我知道只是NumberValue类型的集合,我认为有三种可能的方式可以做到这一点:


非常复杂的通用签名,可以在编译时保留类型信息(我现在正在做什么,并且导致难以维护代码)
将操作移至“值”级别,并:为StringValue抛出unsupportedOperationException,并为NumberValue进行强制转换。
在我确定自己具有NumberValue的位置进行转换,使用稍微复杂一些的泛型来确保这一点。


是否有人有更好的想法或对最佳实践的建议?

最佳答案

正如@tafa所说,在我看来,接口是一个不错的选择。根据您对average的签名,我提出了以下内容。

平均价值

public interface AveragableValue<T> extends Value
{
   public T average(T value);
}


数值

public class NumberValue implements AveragableValue<NumberValue>
{
   private int _n;
   public NumberValue(int n)
   {
      this._n = n;
   }

   @Override
   public void doSomething()
   {
      // from Value interface
   }

   @Override
   public NumberValue average(NumberValue value)
   {
      return new NumberValue((this._n + value._n) / 2);
   }
}


然后,您可以将集合设为AveragableValue类型。在您的代码中,您必须已经在某处具有某种if/else子句以区分NumberValueStringValue以确定是否调用average。因此,我不认为这会变得更加复杂。层次结构有意义-AveragableValueValue的子类型,而NumberValueAveragableValue的类型。

但是,average的签名看起来不正确。它仅接受2个值(this和参数)并将其取平均值。然后,您将丢失之前平均的总事物数。因此,假设整数作为值(如我所做的那样),则如下所示:

(new NumberValue(4)).average(new NumberValue(8)).average(new NumberValue(12));


将为您提供值9而不是8。这是你想要的吗?就像您对集合所做的那样,它使许多迭代计算变得很糟糕。

如果您向我们展示了一些代码-这些类的使用方式,保存它们的集合,您现在的平均状况-我可能会给出更好的答案。

10-07 13:01