I have following code:
public class A {
private String type;
String getType() { return type;}
}
Now in many code places I have code like this
switch (a.geType()) {
case "A" : return new Bla();
case "B" : return new Cop();
}
or somewhere else
switch (a.geType()) {
case "A" : return new Coda();
case "B" : return new Man();
}
(Note that I know I should use an Enumeration in production code).
What I want to achive is that when a new type is added to class A the compiler should flag all the switch statements that need to be adjusted?
Is there a java idiomatic way to do this?
Luckily, JavaScript's object literals are a pretty good alternative for most switch statement use-cases I can think of. The idea is to define an object with a key for each case you would have in a switch statement. Then you can access its value directly using the expression you would pass to the switch statement.
Guarded patterns enable us to avoid additional if conditions in switch statements. Instead, we can move our conditional logic to the case label.
Using “switch” is not an anti-pattern.
when a new type is added to
class A
the compiler should flag all theswitch
statements that need to be adjusted?
A good approach to this would be replacing switch
statements with a more robust implementation of multiple dispatch, such as the Visitor Pattern:
interface VisitorOfA {
Object visitA(A a);
Object visitB(B b);
}
class A {
Object accept(VisitorOfA visitor) {
return visitor.visitA(this);
}
}
class B extends A {
Object accept(VisitorOfA visitor) {
return visitor.visitB(this);
}
}
With this infrastructure in place, you can remove your switch
statements, replacing them with implementations of the visitor:
Object res = a.accept(new VisitorOfA() {
public Object visitA(A a) { return new Bla(); }
public Object visitB(B b) { return new Cop(); }
});
When you add a new subtype to A
, say, class C
, all you need to do is adding a new method to VisitorOfA
:
Object visitC(C c);
Now the compiler will spot all places where this new method has not been implemented, helping you avoid problems at runtime.
Don't forget about good old-fashioned polymorphism. Having a "type" field with switch statements in a class is often a smell that indicates that subclassing might be useful. Consider:
public abstract class CommonSuperClass {
public abstract One getOne();
public abstract Two getTwo();
}
public class A extends CommonSuperClass {
@Override public One getOne() { return new Bla(); }
@Override public Two getTwo() { return new Coda(); }
}
public class B extends CommonSuperClass {
@Override public One getOne() { return new Cop(); }
@Override public Two getTwo() { return new Man(); }
}
If you were to add a new subclass C, you're required to provide implementations for the abstract methods (unless you make C itself be abstract).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With