问题
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?
回答1:
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.
回答2:
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).
回答3:
You could have a map of string / suppliers:
Map<String, Supplier<Object>> map = new HAshMap<> ();
map.put("A", Bla::new);
map.put("B", Cop::new);
And your sample code would become:
return map.get(a.getType()).get(); //need null check
回答4:
In perspective of abstraction, there is another approach for you to use. One way is via Polymorphism as shown here.
Some simple example:
public void EverythingYouWant (Animal animal) {
return animal.move();
}
When it's more about refactoring replace type code/checking with State/Strategy patterns. It's good solution to first consider is there any reason that prevents subclassing.
来源:https://stackoverflow.com/questions/25873571/can-somebody-recommend-a-java-8-pattern-to-replace-a-switch-statement