Java: immutable to immutable conversions
I was thinking about ways to provide syntactic sugar for the framework I was working on. I only want to deal with Immitable objects.
Let's say I have an immutable object and want to create a modified version of it. Would you think a non-instantiated class with a single static factory method would violate OO principles?
String is used as an example:
public final class LOWERCASE { private LOWERCASE() {} public static String string( final String STRING ) { return STRING.toLowerCase(); } }
So from this example I could write:
String lowercaseString = LOWERCASE.string( targetString );
Which I find very readable.
Any reservations against this approach?
source to share
I don't think it's a good idea to create one class for each method. Instead, you can create a class of static methods named for example StringUtils and implement the methods. This way you would call:
String lowerCaseString = StringUtils.lowercase (targetString);
This will also offer you intellisense help as you type. The list of your classes would otherwise be too long. Even for this simple example, you must implement more than one lowercase class so that you can also account for the circumstances that CulutureInfo must consider.
I don't think this violates OO principles, or bad design. In other languages, like Ruby, you can add your methods directly to the String class. Methods that end! means the original object has been modified. All other methods return a modified copy. The Ruby on Rails framework adds some methods to the String class, and there is some debate as to whether this is a good technique or not. It's definitely handy, but.
source to share
Usually on immutable objects, I will have a method that returns the modified version of the object. Therefore, if you have an immutable collection, it might have a sort () method that returns a new sort that is sorted. However, in the String example, this is not possible, since you cannot touch the String class.
Your approach is quite readable, and I think that's fine for cases like this. For immutable objects that you write yourself, I would have a method on the object itself.
By the way, Eric Lippert's series on immutable objects in C # is not bad.
source to share
In my opinion, the only point of such a factory class would be if the class provided different types of immutable objects.
Example:
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 );
}
}
Otherwise, you must implement your method in the immutable class itself, for example toLowerCase () in String Class.
In any case, I don't think it violates any OO principle.
source to share
I agree with Eric. Immutable objects should always have a method that returns a modified version of the object, not a static method. There are also examples in the JDK:
- String.substring (integer)
- BigDecimal.movePointLeft (integer)
Doing it this way has the advantage that you don't need to pass the instance you want to modify as an argument to the method. For classes like String or Integer, I would prefer to use a wrapper class. Then you can control when such an object is created (by the constructor of the wrapper class or one of the methods of the class). If you use the Integer class, it is much more difficult to manage this, since anyone can instantiate this object.
On the other hand, you, for example, find some useful classes like StringUtils of apache commons-lang package. Just take a look at this as I think you wanted to create something like this. (Don't reinvent the wheel)
source to share
new String()
- code smell - it is almost always unnecessary due to immutability String
. If an instance String
has a value, that instance will never have a different meaning.
The following method new String()
is redundant:
public static String string( final String string ) {
return new String( string.toLowerCase() );
}
toLowerCase()
returns a new (different) String
instance - new String()
does nothing useful here other than the reason for another object creation having the exact value of the instance String
returnedtoLowerCase()
Here's a small Groovy script showing the concept (hopefully notice it's Java under the scripting language):
String a = 'CamelCase'
String b = a.toLowerCase()
println "a='${a}'"
println "b='${b}'"
production
a='CamelCase'
b='camelcase'
Notice that a
it hasn't changed - it's unchanged; b
- new meaning String
.
The same is true for BigDecimal.movePointLeft()
or any other method on BigDecimal
that returns BigDecimal
- these are new instances, leaving the original instance unchanged.
OK, now to answer your question:
Having a set of operations for Strings
that are useful in your application is a great idea. Using a factory is probably not required for something like String
, but it might be for another immutable class that takes some work to create.
In a case where it is not possible to extend the base class, for example the String
class static method
described by @kgiannakakis is fine.
Otherwise, if the "immutable" class is part of the application where you have access to the class declaration / definition, methods returning a new instance in the model BigDecimal
, String
etc. would be preferable. This is essentially what @Erik Hesselink, @Bruno Conde and @reallyinsane said.
source to share