I have a need to do some processing from a format A to a format B and from B to A. The job in one direction is very similar to its counterpart. Both formats are represented with an interface Msg
.
In such a case, I can see four obvious solutions, which is the cleanest? I hope there are some concrete principles explaining one choice over the others and not just personal preferences
Here are the obvious choices
1) Different classes for each
public class TransformToA {
public TransformToA() {
...
}
public Msg transform(Msg incoming) {
...
}
}
public class TransformToB {
public TransformToB() {
...
}
public Msg transform(Msg incoming) {
...
}
}
Note that in this option, I could extract some common logic into a third common class to avoid code duplication
2) A boolean field to define the direction
public class Transformer {
private boolean toBFormat;
public Transformer(boolean toBFormat) {
...
}
public Msg transform(Msg incoming) {
if (toBFormat) {
...
} else {
//to A format
}
}
}
3) a boolean flag on the method (this is probably the worst since the caller is forced to pass the flag every single time and makes a method behave in two different ways)
public class Transformer {
public Transformer() {
...
}
public Msg transform(Msg incoming, boolean toBFormat) {
if (toBFormat) {
...
} else {
//to A format
}
}
}
4) Two different methods
public class Transformer {
public Transformer() {
...
}
public Msg transformToA(Msg incoming) {
...
}
public Msg transformToB(Msg incoming) {
...
}
}
5
You’re describing a sort of copy constructor: using one Msg
instance to construct another. I would implement it as such, finding another place to put common helper functionality.
public class A implements Msg {
public A(Msg msg){...}
}
public class B implements Msg {
public B(Msg msg){...}
}
However, you’ve been vague about your reasons for doing the transformation, and I suspect there’s another issue going on. It feels like you might be trying to do too much in the A
and B
classes. Perhaps you should split Msg
into its own class that acts only as a model, then have A
and B
act more as a view, with only the functionality where it matters what format it’s in.
For example, if Msg
was a spreadsheet document, and A
and B
are Excel or OpenDocument formats, then you would want to do the vast majority of your work in your internal Msg
format, and only create an A
or B
when you’re reading or writing your document to disk.
Many clean solution exist.
My pick in Java would definitely be the following structure:
public abstract class AbstractTransform {
... do whatever is the same in all transformer,
or if the constructor would be the same etc...
protected void iDoThisAllTheTime(){
... boring, repeating codes come here
}
public Msg transform(Msg incoming);
}
then just extend this abtract class, and implement the missing method:
public class TransformToA extends AbstractTransform {
@Override
public Msg transform(Msg incoming){
... do the transformation
iDoThisAllTheTime();
}
}
Advatanges:
- easy to extend in a way you want. If you need some additional one, just extend once more.
- documents itself, you need to document pretty much only the Abstract one to say what is it for. The rest of classes will do the same.
- if you need common logics, you can implement it in abstract class, you will avoid duplications. You can implement protected methods for common use and invoke them in child classes.
- not complicated. You don’t need to juggle with classes, interfaces if the task is simple, your code can stay simple.