想象一下完全不可变的任何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 回答
使用静态方法可以防止两件事:
用大多数模拟框架模拟类
覆盖子类中的方法
根据具体情况,这些东西都可以,但从长远来看,它们也会造成严重的悲痛 .
因此,就我个人而言,我只有在有充分理由这样做时才使用静电 .
尽管如此,考虑到问题中的特定Point2D类,我倾向于实际使用静态方法 . 这个类闻起来应该有"value"语义,因此相同坐标的两个点相等并且具有相同的哈希码 . 我也看不出你如何有意义地扩展这个课程 .
想象一下例如Matrix2D类 . 在那里考虑子类可能很有意义,例如SparseMatrix . 然后,最有可能的是,您希望覆盖计算密集型方法!
两者之间没有实际区别 . 最重要的是OO设计和可读性领域 .
静态版本的操作似乎与静态工厂模式更加一致 . 除了使用通用设计模式之外,它还是一个清晰的创作设计,似乎符合其意图: create 一个新的对象 .
另一方面,创建新对象的实例方法在涉及不可变对象时非常实用 . 最好的例子是
String
方法(String.concat(string)
等) . 在我看来,这更多是一个实用性的问题(你不想改变对象的状态;你需要增加它,但操作必须导致一个新的实例) .可能存在一个比另一个更适合的情况(例如,我更喜欢静态方法到流管道中的实例版本的减少 - 作为示例),但是没有明显的,绝对的偏好在这里声明 . 所以...
我会使用静态方法进行工厂操作(虽然为了清楚起见,我将这个方法更像是
create...
,newInstance...
)我会将实例方法用于返回新实例的转换操作,以避免变异对象 .
首先,如果它是一个不可变的,那么它就不会被其他人所取代 . 通常使用
final
,但您可以隐藏构造函数 . 在这种情况下并不特别相关,但静态创建方法允许常用值为重用实例,选择专家实现并且省略丑陋的钻石(<>
)符号 . (如果调用静态创建方法of
,则在使用类型名称限定时可以使用它 . )添加通常写为中缀 . 如果涉及子表达式,这将使客户端代码看起来更好,尽管Java语法仍然会迫使您在任何地方都有括号 . 静态方法需要对客户端进行限定或
import static
(如果方法的名称类似and
则后者不是很有用,如果没有合格的其他静态方法没有意义,则'import *'是不好的) .保留静态方法,用于在某种意义上,对象是函数附带的情况 . 例如
String
的join
和format
.至于测试,不必模拟值类或静态方法 . 不可变类型应该具有可信实现,因此不能被其他人子类型化 .