Writing a method to 'transform' an immutable object: how should I approach this?
Posted
by
Prog
on Programmers
See other posts from Programmers
or by Prog
Published on 2014-06-05T17:34:45Z
Indexed on
2014/06/05
21:40 UTC
Read the original article
Hit count: 155
(While this question has to do with a concrete coding dilemma, it's mostly about what's the best way to design a function.)
I'm writing a method that should take two Color objects, and gradually transform the first Color into the second one, creating an animation. The method will be in a utility class.
My problem is that Color is an immutable object. That means that I can't do color.setRGB
or color.setBlue
inside a loop in the method.
What I can do, is instantiate a new Color and return it from the method. But then I won't be able to gradually change the color.
So I thought of three possible solutions:
1- The client code includes the method call inside a loop. For example:
int duration = 1500; // duration of the animation in milliseconds
int steps = 20; // how many 'cycles' the animation will take
for(int i=0; i<steps; i++) color = transformColor(color, targetColor, duration, steps);
And the method would look like this:
Color transformColor(Color original, Color target, int duration, int steps){
int redDiff = target.getRed() - original.getRed();
int redAddition = redDiff / steps;
int newRed = original.getRed() + redAddition;
// same for green and blue ..
Thread.sleep(duration / STEPS); // exception handling omitted
return new Color(newRed, newGreen, newBlue);
}
The disadvantage of this approach is that the client code has to "do part of the method's job" and include a for
loop. The method doesn't do it's work entirely on it's own, which I don't like.
2- Make a mutable Color
subclass with methods such as setRed
, and pass objects of this class into transformColor
. Then it could look something like this:
void transformColor(MutableColor original, Color target, int duration){
final int STEPS = 20;
int redDiff = target.getRed() - original.getRed();
int redAddition = redDiff / steps;
int newRed = original.getRed() + redAddition;
// same for green and blue ..
for(int i=0; i<STEPS; i++){
original.setRed(original.getRed() + redAddition);
// same for green and blue ..
Thread.sleep(duration / STEPS); // exception handling omitted
}
}
Then the calling code would usually look something like this:
// The method will usually transform colors of JComponents
JComponent someComponent = ... ;
// setting the Color in JComponent to be a MutableColor
Color mutableColor = new MutableColor(someComponent.getForeground());
someComponent.setForeground(mutableColor);
// later, transforming the Color in the JComponent
transformColor((MutableColor)someComponent.getForeground(), new Color(200,100,150), 2000);
The disadvantage is - the need to create a new class MutableColor
, and also the need to do casting.
3- Pass into the method the actual mutable object that holds the color. Then the method could do object.setColor
or similar every iteration of the loop.
Two disadvantages:
A- Not so elegant. Passing in the object that holds the color just to transform the color feels unnatural.
B- While most of the time this method will be used to transform colors inside JComponent
objects, other kinds of objects may have colors too. So the method would need to be overloaded to receive other types, or receive Object
s and have instanceof
checks inside.. Not optimal.
Right now I think I like solution #2 the most, than solution #1 and solution #3 the least. However I'd like to hear your opinions and suggestions regarding this.
© Programmers or respective owner