Using Enums For Descriptive Behavior Grouping
Recently i stumbled upon Javin Pauls interview questions article about enums and although i knew almost everything about it i stopped when i saw the question "Can Enum implement interface in Java". I already had used that feature in several projects but more as a marker interface or to provide a more generic way for a module. But this i time recognized the full effect when it comes to grouping behavior via inheritance.
Consider the following Calculator:
1 public interface Calculator {
2 default double add(int a, int b){
3 return a + b;
4 }
5 }
Now lets assume that there are several other functional calculators where some of them have the same business logic and therefore can be grouped together. Usually (the cleancode way ;) an interface or abstract class is used which can be implemented. In practice this sometimes leads to empty implementation classes to declare that an implementation exists. But i think it could be improved through the use of enums in the following way:
1 public enum BadCalculatorsEnum implements Calculator {
2 Bank, InsuranceCompany, Hydra;
3
4 @Override
5 public double add(int a, int b) {
6 return a + b - 0.001;
7 }
8 }
To be honest with you this practice has some drawbacks:
- Since enums can not be extended it can only be used for potential leaf nodes of your inheritance tree
- In some way it violates the open closed principle when a new group member is added. But i think it is debatable if business logic is not touched.
And last but not least the test...the beauty of Java8, JUnit and AssertJ.
1 @RunWith(Parameterized.class)
2 public class CalculatorTest {
3
4 @Parameters
5 public static Collection<Object[]> data() {
6 List<Object[]> data = stream(BadCalculatorsEnum.values())
7 .map(c -> new Object[] { c, 0.001 })
8 .collect(toList());
9 data.add(new Object[] { new Calculator() {}, 0 });
10 return data;
11 }
12
13 @Parameter
14 public Calculator calculator;
15 @Parameter(1)
16 public double offset;
17
18 @Test
19 public void testAdd() throws Exception {
20 assertThat(calculator.add(1, 3)).isCloseTo(4, offset(offset));
21 }
22 }