Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 521
jack Avatar asked Sep 16 '14 16:09

jack


People also ask

What can I use instead of a switch statement?

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.

What do guarded patterns allow us to do in the pattern matching for switch preview feature?

Guarded patterns enable us to avoid additional if conditions in switch statements. Instead, we can move our conditional logic to the case label.

Is switch an anti pattern?

Using “switch” is not an anti-pattern.


2 Answers

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.

like image 149
Sergey Kalinichenko Avatar answered Sep 16 '22 17:09

Sergey Kalinichenko


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).

like image 35
Stuart Marks Avatar answered Sep 17 '22 17:09

Stuart Marks