1

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

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


作为使用字符串的示例:

public final class LOWERCASE {
  
    private LOWERCASE() {}
  
    public static String string( final String STRING ) {
   
      return STRING.toLowerCase();
    }
}

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

String lowercaseString = LOWERCASE.string( targetString );

我觉得这很可读。


对这种方法有任何附带条件吗?

4

5 回答 5

4

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

String lowerCaseString = StringUtils.lowercase(targetString);

这也会在您打字时为您提供智能感知帮助。否则,您的课程列表将变得太大。即使对于这个简单的示例,您也应该实现多个小写类,以便您还可以满足必须考虑 CulutureInfo 的情况。

我不认为这以任何方式违反了面向对象的原则,或者那是糟糕的设计。在其他语言中,例如 Ruby,您可以将方法直接添加到 String 类。以 ! 结尾的方法 表示修改了原始对象。所有其他方法都返回修改后的副本。Ruby on Rails 框架向 String 类添加了一些方法,关于这是否是一种好的技术存在一些争论。不过,它绝对很方便。

于 2008-11-11T12:11:53.723 回答
1

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

您的方法非常易读,我认为对于这样的边缘情况,非常好。对于您自己编写的不可变对象,我将在对象本身上有方法。

顺便说一下, Eric Lippert 关于 C#中不可变对象的系列非常好。

于 2008-11-11T12:03:33.193 回答
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 类中的 toLowerCase()。

无论哪种方式,我都不认为这违反了任何面向对象的原则。

于 2008-11-11T12:25:42.290 回答
1

我同意埃里克的观点。不可变对象应始终具有返回对象修改版本的方法,而不是静态方法。JDK中也有例子:

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

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

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

于 2008-11-11T12:28:11.227 回答
1

new String()是一种代码味道-由于. 一旦一个实例有一个值,那个实例就永远不会有不同的值。StringString

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

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

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

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

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

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

生产

a='CamelCase'
b='camelcase'

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

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

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

在您的应用程序中拥有一组用于Strings执行有用目的的操作是一个好主意。对于类似的东西可能不需要使用工厂String,但对于需要一些努力构建的不同的不可变类可能是必需的。

在无法扩展基类的情况下,如@kgiannakakis 描述String的s 类就可以了。static method

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

于 2008-11-11T13:25:10.750 回答