代码之家  ›  专栏  ›  技术社区  ›  user44242

处理仅对层次结构的一部分有意义的二进制操作

  •  0
  • user44242  · 技术社区  · 14 年前

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

    有一个平均运算,它只对带有签名的NumberValue有意义

    数值平均值(数值数值数值){ ... }

    在创建这样的变量并在各种集合中使用它们之后,我需要对一个我知道只有NumberValue类型的集合求平均值,我认为有三种可能的方法:

    1. 非常复杂的泛型签名,在编译时保留类型信息(我现在做的事情,导致代码难以维护)
    2. 将操作移动到值级别,并:对StringValue抛出unsupportedOperationException,并对NumberValue进行强制转换。
    3. 在我确信自己有一个数字值的点上进行转换,使用稍微不那么复杂的泛型来确保这一点。

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

    3 回复  |  直到 14 年前
        1
  •  1
  •   Phil    14 年前

    正如@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 要区分的地方 NumberValue StringValue 决定是否打电话 平均的 或者不是。所以我不认为这会更复杂。等级制度是有道理的- 平均价值 s是 Value ,以及 数值 是一种 平均价值 .

    然而,这个签名 平均的 看起来不太对劲。它只需要2个值( this 和论点)并将其平均。然后,你就失去了之前平均值的总数。假设整数是值(就像我做的那样),类似这样:

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

    会给你价值吗 9 而不是 8 .这就是你想要的吗?这对许多迭代进行的计算都是不利的,就像对集合所做的那样。

    如果你向我们展示你的一些代码——这些类是如何使用的,包含它们的集合,你现在是如何平均的——我可能会给出一个更好的答案。

        2
  •  0
  •   tafa    14 年前

    我会创建另一个界面iAverable,其中包含从值派生的平均操作。然后StringValue将只实现Value接口,NumberValue将实现Iaverable。

    然后,当需要使用平均操作时,我会检查对象是否实现了iAverable。

        3
  •  0
  •   Patrick Holthuizen    14 年前

    我无法发表评论,因此我将发布一个新的答案。

    为价值创建一个界面:

    public interface Value<T> {
        public T getValue();
    }
    

    一个是averagable:

    public interface Averagable<T> {
        public T average(T value);
    }
    

    那么一个数值应该是这样的:

    public class NumberValue implements Averagable<Number>, Value<Number>{
        public Number average(Number value) {
            // do your stuff
        }
    
        public Number getValue() {
            // do your stuff
        }
    }
    

    没有必要让Averagable从价值扩展。