首页 文章

Java中的不可变数据 - 静态或实例运算符?

提问于
浏览
4

想象一下完全不可变的任何Java类 . 我将使用以下作为示例:

public class Point2D {
  public final int x;
  public final int y;

  public Point2D(final int x, final int y) {
    this.x = x;
    this.y = y;
  }
}

现在考虑在这个类上添加一个运算符:一个接受 Point2D 的一个或多个实例的方法,并返回一个新的 Point2D .

这有两种可能性 - 静态方法或实例方法:

public static Point2D add(final Point2D first, final Point2D second) {
  return new Point2D(first.x + second.x, first.y + second.y);
}

要么

public Point2D add(final Point2D other) {
  return new Point2D(this.x + other.x, this.y + other.y);
}

有没有理由选择一个而不是另一个?这两者之间有什么不同吗?据我所知,他们的行为是相同的,所以任何差异都必须是他们的效率,或者他们作为程序员合作的容易程度 .

3 回答

  • 4

    使用静态方法可以防止两件事:

    • 用大多数模拟框架模拟类

    • 覆盖子类中的方法

    根据具体情况,这些东西都可以,但从长远来看,它们也会造成严重的悲痛 .

    因此,就我个人而言,我只有在有充分理由这样做时才使用静电 .

    尽管如此,考虑到问题中的特定Point2D类,我倾向于实际使用静态方法 . 这个类闻起来应该有"value"语义,因此相同坐标的两个点相等并且具有相同的哈希码 . 我也看不出你如何有意义地扩展这个课程 .

    想象一下例如Matrix2D类 . 在那里考虑子类可能很有意义,例如SparseMatrix . 然后,最有可能的是,您希望覆盖计算密集型方法!

  • 1

    两者之间没有实际区别 . 最重要的是OO设计和可读性领域 .

    静态版本的操作似乎与静态工厂模式更加一致 . 除了使用通用设计模式之外,它还是一个清晰的创作设计,似乎符合其意图: create 一个新的对象 .

    另一方面,创建新对象的实例方法在涉及不可变对象时非常实用 . 最好的例子是 String 方法( String.concat(string) 等) . 在我看来,这更多是一个实用性的问题(你不想改变对象的状态;你需要增加它,但操作必须导致一个新的实例) .

    有没有理由选择一个而不是另一个?

    可能存在一个比另一个更适合的情况(例如,我更喜欢静态方法到流管道中的实例版本的减少 - 作为示例),但是没有明显的,绝对的偏好在这里声明 . 所以...

    • 我会使用静态方法进行工厂操作(虽然为了清楚起见,我将这个方法更像是 create...newInstance...

    • 我会将实例方法用于返回新实例的转换操作,以避免变异对象 .

  • 2

    首先,如果它是一个不可变的,那么它就不会被其他人所取代 . 通常使用 final ,但您可以隐藏构造函数 . 在这种情况下并不特别相关,但静态创建方法允许常用值为重用实例,选择专家实现并且省略丑陋的钻石( <> )符号 . (如果调用静态创建方法 of ,则在使用类型名称限定时可以使用它 . )

    添加通常写为中缀 . 如果涉及子表达式,这将使客户端代码看起来更好,尽管Java语法仍然会迫使您在任何地方都有括号 . 静态方法需要对客户端进行限定或 import static (如果方法的名称类似 and 则后者不是很有用,如果没有合格的其他静态方法没有意义,则'import *'是不好的) .

    保留静态方法,用于在某种意义上,对象是函数附带的情况 . 例如 Stringjoinformat .

    至于测试,不必模拟值类或静态方法 . 不可变类型应该具有可信实现,因此不能被其他人子类型化 .

相关问题