Blog-Archiv

Freitag, 7. Oktober 2016

How to Avoid Switch Statements in Java

A refactoring that has been made popular by Martin Fowler is "Replace Switch-Statements by Polymorphism". We learn that wherever a switch statement is, OO thinking has been absent.

This impressive refactoring has been described on the Internet many times. It demonstrates the power of OO thinking in an unique way. Here comes my contribution.

Smelling Switch Code

Two types of employees exist, ENGINEER gets the base salary, MANAGER gets more, because (s)he is more equal. The distinction is done by a switch-case statement that uses the constructor parameter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Employee
{
    public static final int ENGINEER = 1;
    public static final int MANAGER = 2;

    private final int monthly = 100;
    private final int bonus = monthly / 10;

    private final int type;

    public Employee(int type) {
        if (type < ENGINEER || type > MANAGER)
          throw new IllegalArgumentException("Unknown employee type: "+type);

        this.type = type;
    }

    public int salary() {
        switch(type) {
            case ENGINEER: return monthly;
            case MANAGER: return monthly + bonus;
        }
    }
}

We could test this with following code:

final Employee engineer = new Employee(Employee.ENGINEER);
assert engineer.salary() == 100;

final Employee manager = new Employee(Employee.MANAGER);
assert manager.salary() == 110;

Aside from the social smell the question rises whether it is acceptable to implement two types of employees in the same class (type). OO-thinking people have provided an impressive alternative.

Refactored using Sub-Classes

The rewrite is scattered across several classes, but it is not longer than the code above.

1
2
3
4
5
6
abstract class AbstractEmployee
{
    protected final int monthly = 100;

    public abstract int salary();
}

1
2
3
4
5
6
7
8
public class Engineer extends AbstractEmployee
{
    @Override
    public int salary() {
        final int bonus = monthly / 10;
        return monthly + bonus;
    }
}

1
2
3
4
5
6
7
public class Manager extends AbstractEmployee
{
    @Override
    public int salary() {
        return monthly;
    }
}

To be tested by:

final Employee engineer = new Engineer();
assert engineer.salary() == 110;

final Employee manager = new Manager();
assert manager.salary() == 100;

As you can see, this is intuitively readable and much cleaner.
Even the social smell has been refactored :-)




Keine Kommentare: