如何调用与不可变对象一起使用的类工厂 (java) 方法
当为“不可变对象”创建类时,不可变意味着实例的状态不能更改;在 Java(和类似语言)中,在构造函数中分配的所有字段,有时仍然允许创建修改后的实例很有用。也就是说,使用一个实例作为基础,并创建一个仅与一个属性值不同的新实例;来自基本实例的其他值。举一个简单的例子,可以有这样的类:
public class Circle {
final double x, y; // location
final double radius;
public Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
// method for creating a new instance, moved in x-axis by specified amount
public Circle withOffset(double deltaX) {
return new Circle(x+deltaX, y, radius);
}
}
那么:应该调用什么方法“withOffset”? (注意:不是它的名称应该是什么——而是此类方法的名称是什么)。 从技术上讲,它是一种工厂方法,但不知怎的,这对我来说似乎不太正确,因为工厂通常只被赋予基本属性(并且要么是静态方法,要么不是结果类型的成员而是工厂类型)。
所以我猜这种方法应该有一个更好的术语。由于这些方法可以用来实现“流畅接口”,也许它们可以是“流畅工厂”方法”? 更好的建议?
编辑:正如答案之一所建议的,java.math.BigDecimal
是一个很好的例子,它具有“add”、“subtract”(等)方法。
另外:我注意到有 这个问题(由 Jon Skeet 提出)有点相关(尽管它询问方法的具体名称)
编辑,2014 年 5 月:我目前最喜欢的是突变工厂
, FWIW。
When creating classes for "immutable objects" immutable meaning that state of instances can not be changed; all fields assigned in constructor) in Java (and similar languages), it is sometimes useful to still allow creation of modified instances. That is, using an instance as base, and creating a new instance that differs by just one property value; other values coming from the base instance. To give a simple example, one could have class like:
public class Circle {
final double x, y; // location
final double radius;
public Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
// method for creating a new instance, moved in x-axis by specified amount
public Circle withOffset(double deltaX) {
return new Circle(x+deltaX, y, radius);
}
}
So: what should method "withOffset" be called? (note: NOT what its name ought to be -- but what is this class of methods called).
Technically it is kind of a factory method, but somehow that does not seem quite right to me, since often factories are just given basic properties (and are either static methods, or are not members of the result type but factory type).
So I am guessing there should be a better term for such methods. Since these methods can be used to implement "fluent interface", maybe they could be "fluent factory methods"?
Better suggestions?
EDIT: as suggested by one of answers, java.math.BigDecimal
is a good example with its 'add', 'subtract' (etc) methods.
Also: I noticed that there's this question (by Jon Skeet no less) that is sort of related (although it asks about specific name for method)
EDIT, MAY-2014: My current favorite is mutant factory
, FWIW.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我将这些类型的方法称为“复制方法”。
虽然
clone()
方法创建精确的副本,但复制方法会创建实例的副本,通常带有隐式或显式变体。例如,String#toUpperCase()
是不可变 String 类的复制方法 - 它复制一个具有变体的实例:它会将所有字母大写。我认为您的示例中的
withOffset()
方法是类似的复制方法。我不知道有任何参考资料记录了术语“复制方法”。我借用了 C++ 中的“复制”一词:复制构造函数和 Taligent 编码标准中的“复制”命名指南 (更多信息)。
至于术语“流畅的工厂方法”,我不知道为什么“流畅的”会产生影响,因为“流畅的接口”只是一种 API 样式(与构建器模式分开)。如果“工厂方法”这个术语在这里不适用,我不明白称其为“流畅的工厂方法”如何使它更好地适用。
I call those types of methods "copy methods".
While the
clone()
method creates an exact copy, a copy method makes a copy of an instance, usually with an implied or explicit variation. For example,String#toUpperCase()
would be a copy method of the immutable String class - it copies an instance with a variation: it upcases all the letters.I would consider
withOffset()
method in your example to be a similar copy method.I don't know of any references that document the term "copy method". I'm borrowing the term "copy" from its use in C++: copy constructors and the "copy" naming guideline from the Taligent Coding Standards (more info).
As for the term "fluent factory methods", I don't know why "fluent" would make a difference, since a "fluent interface" is just an API style (separate from the builder pattern). If the term "factory method" doesn't apply here, I don't see how calling it a "fluent factory method" makes it apply any better.
嗯……它创建了该对象的突变版本……也许我们应该称其为突变工厂? :-)
Hrm … it creates mutated versions of the object … maybe we should call it a mutant factory? :-)
这看起来并不像工厂方法。 单独的签名只告诉我我可以将它链接到不同的调用中,但并不是说它应该创建一个新实例:
我认为这个用例更像是一个允许append(“a”).append(“b”)的StringBuilder。
当然,它每次都可以返回一个新的 StringBuilder (就像你的 Circle 所做的那样)。
所以这不是一个设计工厂。 (考虑提取接口并为该方法编写 JavaDoc:“必须返回一个新实例,因为我是不可变的”——为什么会这样?)您的类是不可变的这一事实只是一个实现细节)。
编辑:
更好的例子是 BigInteger,因为它也是不可变的。与 multiply(BigInteger) 一起,它提供了一个包私有方法:
它返回一个新实例并且非常类似于您的情况。这只是一个恰好返回与初始对象类型相同的结果的操作;不是工厂,我不认为这种操作真正名副其实。
This does not really look like a factory method. The signature alone only tells me that I can chain it in different calls, but not that it is supposed to create a new instance:
I see this use case more like a StringBuilder that allows append("a").append("b").
It could, of course return a new StringBuilder every time (as your Circle does).
So it's not by design a factory. (Think of extracting the interface and writing the JavaDoc for that method: "one must return a new instance, since I'm immutable" -- why so ??) The fact that your class is immutable is just an implementation detail).
EDIT:
Perahs a better example would be BigInteger, since that's also immutable. Along with multiply(BigInteger), it provides a package-private method:
which returns a new instance and resembles your case very well. That's simply an operation that happens to return a result of the same type as the initial object; not a factory and I don't think this kind of operation really deserves its own name.