不可变类的静态方法与非静态方法
给出下面的类定义。如何决定存根方法应该是静态的还是非静态的?
class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// Should the methods add(), subtract() and inverseOf() be non-static ...
public Point add(Point point) {
}
public Point subtract(Point point) {
}
public Point inverseOf() {
}
// Or static?
public static Point add(Point point1, Point point2) {
}
public static Point subtract(Point point1, Point point2) {
}
public static Point inverseOf(Point point) {
}
}
Given the class definition below. How would one go about deciding whether the stub methods should be static or non-static?
class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// Should the methods add(), subtract() and inverseOf() be non-static ...
public Point add(Point point) {
}
public Point subtract(Point point) {
}
public Point inverseOf() {
}
// Or static?
public static Point add(Point point1, Point point2) {
}
public static Point subtract(Point point1, Point point2) {
}
public static Point inverseOf(Point point) {
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
我会去寻找实例方法。然后,您就可以将这些方法作为接口的一部分并覆盖它们。当您必须处理 2d 点或 3d 点并且有一些并不真正关心并且只需要对实现接口的点执行操作的客户端代码时,您会受益匪浅。
I would go for instance methods. You then have the capacity of making the methods part of an inteface and override them. You would get the benefit when you have to deal with 2d points or 3d points and have some client code that doesn't really care and just need to perform operations on Points implementing the interface.
我认为这取决于您想要实现的目标。如果您提供将任意两点相加的方法,那么您需要一个静态方法。但是,如果您想要一个将点添加到给定 Point 实例的方法,那么您需要一个非静态方法。
如果您确实使用静态方法,那么您可以考虑将静态方法放入仅包含静态方法的单独实用程序类(PointCalculator)中。这与数学课类似。
I think it depends on what you are trying to accomplish. If you are providing a method that adds any two points together then you want a static method. But if you want a method that adds a point to a given Point instance then you want an non-static method.
If you do use a static methods then you could consider putting the static methods into a separate utility class (PointCalculator) that only contains static methods. This is similar to the Math class.
我会选择更面向对象的非静态方法(是的,使用太多静态方法会破坏多态性、继承等对象的好处......),即使您的 Point 是不可变的。实际上,这与 BigDecimal 或 BigInteger 等类的设计方式是一致的。最重要的是,静态方法使类变得更加困难来测试,所以我宁愿尽可能避免使用它们,特别是当它有意义时。
I'd go for non-static methods which are more object oriented (yes, using too many static method breaks the benefit of objects like polymorphism, inheritance...), even if your
Point
is immutable. And actually, this would be consistent with the way classes likeBigDecimal
orBigInteger
are designed. On top of that, static methods make classes harder to test so I prefer to avoid using them if possible, especially when it makes sense.从语义上讲,静态方法似乎更有意义。当然,两者都可以工作,但非静态方法使一个点优先于另一个点,并且还意味着 point1(调用 add 的方法)可能会因调用的结果而被修改。
作为使用您的类的开发人员,如果我看到以下内容:
或者..
我的自然倾向是假设非静态版本中的 add() 方法修改 point1 以添加点 2 的结果。使用静态方法,更清楚(尽管不能保证!)该方法是纯粹的并且代表点没有被修改。
Semantically, the static approach seems to make a bit more sense. Both will of course work, but the non-static approach gives precedence to one point over another, and furthermore implies that point1 (the method which add is called on) may be modified as a result of the call.
As a developer using your classes, if I saw the following:
or..
my natural inclination would be to assume that the add() method in the non-static version modifies point1 to add the result of point 2. With the static approach, it's more clear (although not guaranteed!) that the method is pure and the represenative points are not being modified.
当方法主体不依赖于任何一个特定实例时,请使用静态方法。
作为一个示例,请查看您的
add(Point, Point)
方法。您将作为参数传递给函数的两个Point
加在一起,并返回另一个Point
。这真的需要一个对某些Point
的内部this
引用吗?另一方面,您有一个方法
add(Point)
。据推测,这会将函数参数添加到实例中 - 在这种情况下,您必须将其设为实例方法,以便拥有两个 Point。编辑:我想我最初误解了。回顾过去,您拥有静态和非静态实现的正确签名。在这一点上,我想说这是一个风格问题,因为你知道两者都会正常工作。您希望如何使用您的积分类别?想想
Point a = Point.add(b, c)
或Point a = b.add(c)
是否会让代码更直观。就我个人而言,我喜欢前者,因为它告诉我两个操作数都不会被修改。Use a static method when the body of the method does not depend on any one particular instance.
As one example, look at your
add(Point, Point)
method. You are adding together the twoPoint
s that are passed to the function as arguments, and returning anotherPoint
. Does this really need an internalthis
reference to somePoint
?On the other hand, you have a method
add(Point)
. Presumably this adds the function argument to the instance - in that case, you would have to make this an instance method so you have bothPoint
s.Edit: I think I misunderstood, originally. Looking back, you have the correct signatures for both the static and non-static implementations. At this point, I would say it is a matter of style, as you know both will work correctly. How do you want your point class to be used? Think of whether it makes the code more intuitive to say
Point a = Point.add(b, c)
orPoint a = b.add(c)
. Personally, I like the former, as it tells me that neither of the operands is going to be modified.很自然,这些函数必须是非静态的。但如果你有疑问,请参考 GRASP,他们描述了这样的事情。
根据 GRASP 信息专家,这些函数不应该是静态的。
尽管事实上没有关于静态方法的直接信息,但有
如果您将方法设置为静态,您将使逻辑远离实际数据,并且必须将数据传递给方法。
删除静态将使逻辑更接近它使用的数据。
It is naturally that these functions has to be non static. But if you doubt please refer to GRASP, they describe things like this.
According to GRASP Information Expert these functions shouldn't be static.
Despite the fact there is no direct information about the static method, there is
If you make you methods static you will move your logic further from actual data and will have to pass data to method.
Removing static will put logic closer to data it uses.
如果您打算使用 Java 并创建对象,那么从风格上来说,我认为您应该尝试最大限度地利用对象和数据封装。对我来说,这意味着将数据保留在原来的位置(在 Point 类中),而不是将其传递给单独的方法来处理它。让你的物品为你服务;不仅仅是 getter 和 setter。事实上,请认真思考如何才能完全避免需要 getter。
在不可变类上使用 add() 和 minus() 等方法返回不可变类的新实例是非常常见的。对于类似 FP 的编程来说,这是很好的风格,对于这样的类来说也是完全合理的。 (请参阅 BigInteger 或 BigDecimal 以获得好的示例。不要查看 Date 或 Calendar 以获得糟糕的可怕示例。:)
在类中保留方法可以让您选择定义这些类可能实现的接口,使用装饰器或适配器模式,编写某些类型的测试等
If you're going to use Java and create objects, then stylistically, I think you should try to make maximal use of objects and data encapsulation. To me, that means leaving the data where it is (in the Point class) and not passing it to a separate method to deal with it. Make your objects work for you; not just have getters and setters. In fact, think hard about how you can avoid needing a getter at all.
It is perfectly common to have methods like add() and subtract() on an immutable class that return new instances of the immutable class. This is good style for FP-like programming and perfectly reasonable for a class like this. (See BigInteger or BigDecimal for good examples. DON'T see Date or Calendar for bad broken scary examples. :)
Keeping methods in the class lets you optionally define interfaces that these classes might implement, use the Decorator or Adapter pattern, write certain kinds of tests, etc.
我倾向于在这方面违反规范,但无论哪种方式对我来说似乎都是合理的。
对于像 Java 这样的语言,我会使用静态方法,特别是因为上面的第二点。对于具有运算符重载的语言(如 Ruby),我会使用实例方法来利用它。
I tend to run counter to the norm on this, but either way seems reasonable to me.
For a language like Java, I'd go with static methods, specifically because of the second point above. For a language that has operator overloading (like Ruby), I'd go with an instance method to take advantage of that.
使它们静态化也会使单元测试变得更加困难!据我所知,.NET 中唯一可以处理此问题的模拟框架是 TypeMock。
如果目的是使此类不可变,那么您将在任何访问器中返回新的 Point 对象,请调用,因此使它们静态在这里没有多大意义。
Making them static also makes it harder to unit test them! The only mocking framework I am aware of in .NET that could handle this is TypeMock.
If the intention is to make this class immutable, than you will be returning new Point objects in any accessor, call so making them static doesn't make much sense here.
这些方法应该是静态的,因为类本身适合通过构造函数创建,并由于 x 和 y 是最终的而分配一次值。这意味着您可以创建点,但不能操纵其数据。 Add/Substract/Etc 方法是实用方法,不需要使用 Point 实例。
These methods should be static because the Class itself lends itself to being created via the constructor and assigned values once due to x and y being final. This means you can create Points, but not manipulate their data going forward. The Add/Substract/Etc methods are utility methods which should not require an instance of Point to be used.
在您的情况下,它必须是非静态的,除非您将签名更改为 public static Point add(Point point1, Point point2) 。
编辑:我投了反对票。没关系。我并不是想给出诸如将静态放在方法前面之类的琐碎建议。在这种情况下,实例方法更好,但确实没有单一的答案。这仅取决于您的喜好。
In your case it has to be non static unless you change signature to
public static Point add(Point point1, Point point2)
.EDIT : I got down voted. That's fine. I was not trying to give trivial suggestion like putting static in front method. In this case, an instance method is better, but there is really not singe answer. It just depends on your preference.