Java:永远不变的转换

时间:2008-11-11 11:55:10

标签: java static frameworks methods factory

我一直在考虑为我一直在研究的框架提供语法糖的方法。我想专门处理Immitable对象。

假设我有一个不可变对象,并希望创建它的修改版本。在您看来,具有单个静态工厂方法的不可实例化的类是否会违反OO原则?


  

作为使用String的示例:

public final class LOWERCASE {

    private LOWERCASE() {}

    public static String string( final String STRING ) {

      return STRING.toLowerCase();
    }
}
     

因此,从这个例子我可以写:

String lowercaseString = LOWERCASE.string( targetString );
     

我发现它非常易读。


任何反对这种做法的附带条件?

5 个答案:

答案 0 :(得分:4)

我不认为每个方法创建一个类是个好主意。您可以改为创建一个静态方法类,命名为例如StringUtils并实现这些方法。这样你就可以打电话:

String lowerCaseString = StringUtils.lowercase(targetString);

这也可以在您输入时为您提供智能感知帮助。你的课程列表会变得太大了。即使是这个简单的例子,你也应该实现多个小写类,这样你就可以满足CulutureInfo必须考虑的环境。

我认为这不会以任何方式破坏OO原则或者设计不好。在其他语言中,例如Ruby,您可以将方法直接添加到String类中。结束的方法!表示原始对象已被修改。所有其他方法都返回修改后的副本。 Ruby on Rails框架为String类添加了一些方法,并且对于这是否是一种好技术存在争议。这绝对很方便。

答案 1 :(得分:1)

通常在不可变对象上,我会有一个方法返回对象的修改版本。因此,如果您有一些不可变集合,它可以有一个sort()方法,它返回一个已排序的新集合。但是,在您的String示例中,这是不可能的,因为您无法触及String类。

您的方法非常易读,我认为对于这样的边缘情况,完全没问题。对于你自己写的不可变对象,我在对象本身上有方法。

顺便说一下,

Eric Lippert's series on immutable objects in C#非常好。

答案 2 :(得分:1)

在我看来,这样一个工厂类的唯一要点就是该类提供了不同类型的不可变对象。

例如:

public final class Lowercase {

  private Lowercase() {}

  public static String string( final String string ) {

   return new String( string.toLowerCase() );
  }

  public static Foo foo( final Foo f ) {
     boolean isLowerCase = true;
     return new Foo(f, isLowerCase );
  }
}

否则,您应该在不可变类本身中实现您的方法,例如String Class中的toLowerCase()。

无论哪种方式,我认为这不违反任何OO原则。

答案 3 :(得分:1)

我同意Erik的观点。不可变对象应始终具有返回对象的修改版本而不是静态方法的方法。 JDK中还有一些例子:

  • String.subString(int)的
  • BigDecimal.movePointLeft(int)的

这样做的好处是,您不需要将要修改的实例作为方法的参数传递。对于像String或Integer这样的类,我更喜欢使用包装类。然后,您可以控制何时创建此类对象(通过包装类的构造函数或类的某个方法)。如果你要使用Integer类,那么控制它就会复杂得多,因为每个人都可以创建它的实例。

另一方面,你的例子被认为是一些实用程序类,如apache commons-lang包的StringUtils。只是看看这个,因为我认为你想创造这样的东西。 (不要重新发明轮子)

答案 4 :(得分:1)

new String()是代码气味 - 由于String不变性,它几乎总是不必要。一旦String实例具有值,该实例永远不会具有不同的值。

在以下方法中,new String()是多余的:

public static String string( final String string ) {
    return new String( string.toLowerCase() );
}

toLowerCase()返回一个新的(不同的)String实例 - new String()除了导致另一个具有String的确切值的对象创建之外,在此处没有做任何有益的事情toLowerCase()

返回的实例

这是一个显示概念的小Groovy脚本(我希望 - 注意,这是脚本语言下的Java):

String a = 'CamelCase'
String b = a.toLowerCase()

println "a='${a}'"
println "b='${b}'"
制造

a='CamelCase'
b='camelcase'

请注意a 没有改变 - 它是不可变的; b是一个新的String值。

BigDecimal.movePointLeft()BigDecimal上返回BigDecimal的任何其他方法也是如此 - 它们是新实例,原始实例保持不变。

好的,现在回答你的问题:

Strings执行一组在您的应用程序中执行有用目的的操作是个好主意。对String之类的东西来说,使用工厂可能不是必需的,但可能是为了一个需要花费一些精力来构建的不同的不可变类。

如果无法扩展基类,例如String,则描述的@ static method类为@kgiannakakis是正常的。

否则,如果“immutable”类是应用程序的一部分,您可以访问类声明/定义,返回新实例的方法,在BigDecimalString模型中,等等,会更好。这实际上是@Erik Hesselink,@ Bruno Conde和@reallyinsane所说的。