Can somebody recommend a java 8 pattern to replace a switch statement?

我是研究僧i 提交于 2020-12-02 07:23:38

问题


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 the switch 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!