Friday, March 7, 2014

This powerful Enum - part 2

let's move on

Recently I wrote about basics of Enums and when we finally knows them, we can take the next step and look how powerful Enums in Java really are.
Today there will be more code, mostly covered with tests to prove that it works as I wrote :)

what we get with no effort?

Take a look at simple enum:
public enum TDDStep {
    RED, GREEN, REFACTOR;
}

Not so impressive isn't it? But don't worry, even such simple construction gives as a few usefull methods:
@Test
public void stringToEnum() {
    assertEquals(TDDStep.RED, TDDStep.valueOf("RED"));
}
 
@Test
public void enumToString() {
    assertEquals("GREEN", TDDStep.GREEN.toString());
}
 
@Test
public void enumName() {
    assertEquals("REFACTOR", TDDStep.REFACTOR.name());
}
 
@Test
public void enumOrdinal() {
    assertEquals(1, TDDStep.GREEN.ordinal());
}

name() and ordinal() method are simple getters which returns values given in constructor which is emitted by the compiler in response to enum type declarations.
Constructor cannot be invoked by programmer and its declaration looks like this:
protected Enum(String name, int ordinal)

Method toString(), until is not overridden, will return the name of the enum constant, which is more less the same what name() is returning.

Method valueOf() looking for the enum which name is the same as a given value and returns it.

There is also one more method which is worth to mention:
@Test
public void valuesOfEnum() {
    TDDStep[] steps = {TDDStep.RED, TDDStep.GREEN, TDDStep.REFACTOR};
 
    assertArrayEquals(steps, TDDStep.values());
}

I believe that after looking at test there is no need for more explanation :)

In this paragraph I described the most important Enum's method which we just get because of using enum keyword.
Let's see what we can do more with it.

my own methods

Enumeration don't have to be just a simple list of an items. You can add your own method into it or/and provide your own constructor.
It's worth to mention that constructor have to be private and you cannot execute parent's (Enum) costructor, it would be done with no additional effort.

Category enum shows how to do this:
package com.smalaca.enumeration.designpatterns;

public enum Category {

    CREATIONAL("Deals with object creation mechanisms, trying to create objects in a manner suitable to the situation."),
    STRUCTURAL("Eases the design by identifying a simple way to realize relationships between entities."),
    BEHAVIORAL("Identifies common communication patterns between objects and realize these patterns.");
 
    private final String description;

    private Category(final String description) {
        this.description = description;
    }

    public String describe() {
        return description;
    }

    public String getExample() {
  
        String example = "";
  
        switch(this) 
        {
            case CREATIONAL:
                example = "Builder";
                break;
  
            case STRUCTURAL:
                example = "Adapter";
                break;
  
            case BEHAVIORAL:
                example = "Strategy";
                break;  
        }
  
        return example;
    }
}

Believe me or not, but it really works and if you want to verify it just run following tests:
@RunWith(Parameterized.class)
public class CategoryTest {

    private Category category;
    private String description;
    private String example;
 
    public CategoryTest(Category category, String description, String example) {
        this.category = category;
        this.description = description;
        this.example = example;
    }
 
    @Parameters
    public static Collection<Object[]> dataProvider() {
    return Arrays.asList(new Object[][] {
            { 
                Category.CREATIONAL, 
                "Deals with object creation mechanisms, trying to create objects in a manner suitable to the situation.",
                "Builder"
            },
            { 
                Category.STRUCTURAL, 
                "Eases the design by identifying a simple way to realize relationships between entities.",
                "Adapter"
            },
            { 
                Category.BEHAVIORAL, 
                "Identifies common communication patterns between objects and realize these patterns.",
                "Strategy"
            }
        });
    }
 
    @Test
    public void getCategoryExplanation()
    {
        assertSame(description, category.describe());
    }
 
    @Test
    public void getExample()
    {
        assertSame(example, category.getExample());
    }
}

If you are not familiar with @Parameterized annotation in JUnit look here for quick introduction.

gimme little bit of abstraction

Creating abstract methods is really useful from time to time that's why it's possible to do so in enumeration as well:
package com.smalaca.enumeration.designpatterns;

public enum Creational {

    ABSTRACT_FACTORY {
        @Override
        public String describe() {
            return "Provide an interface for creating families of related or dependent objects without specifying their concrete classes.";
        }
    },
 
    BUILDER {
        @Override
        public String describe() {
            return "Separate the construction of a complex object from its representation allowing the same construction process to create various representations.";
        }
    },
 
    FACTORY_METHOD {
        @Override
        public String describe() {
            return "Define an interface for creating a single object, but let subclasses decide which class to instantiate.";
        }
    };
 
    abstract public String describe();
}

Now run:
@RunWith(Parameterized.class)
public class CreationalTest {

    private Creational designPattern;
    private String description;
    
    public CreationalTest(Creational designPattern, String description) {
        this.designPattern = designPattern;
        this.description = description;
    }
    
    @Parameters
    public static Collection<Object[]> dataProvider() {
        return Arrays.asList(new Object[][] {
            { 
                Creational.ABSTRACT_FACTORY, 
                "Provide an interface for creating families of related or dependent objects without specifying their concrete classes.",
            },
            { 
                Creational.BUILDER, 
                "Separate the construction of a complex object from its representation allowing the same construction process to create various representations.",
            },
            { 
                Creational.FACTORY_METHOD, 
                "Define an interface for creating a single object, but let subclasses decide which class to instantiate.",
            }
        });
    }
    
    @Test
    public void getPatternExplanation()
    {
        assertSame(description, designPattern.describe());
    }
}

And? Everything is green, isn't it?

and what about interfaces?

We know how important interfaces are in well designed code. That's why it's great news for all of us that Enums allows for implementation of as many interfaces as you want to, just like regular class.

Let's assume that we have got following interface:
public interface HasDescription {
    public String describe();
}

Now we will change enums definition and add part about implementing newly added interface:
public enum Creational implements HasDescription { /** code */ )

and
public enum Categoryimplements HasDescription { /** code */ )

Now run our tests once again. Is everything still ok? Should be :)

what about inheritance?

Ok, so it's possible to implement interfaces and create abstract methods and what about inheritance?
I believe there is no need for any explanation at the moment, because I already mentioned something about parent in one of the paragraphs above, when I was writing about name() and ordinal() methods and constructor and calling parent in it, but to be exact...

As it's writen in tutorial:
All enums implicitly extend java.lang.Enum. Since Java does not support multiple inheritance, an enum cannot extend anything else.

an empty enum

As a curiosity I want to also write that is possible to create an empty enum and compiler will have no problem with it. Which means that enum below is valid:
public enum KnownAlienRace {}

As a side note, I want to tell you that I didn't use it ever so if you have got any good example which shows that creating enumeration like this have sense share with me in comments, I will appreciate :)

and a few questions for you

This post and the previous one was to show you what we can do with Enums in Java, what for language allows us.
Anyway, there will be at least one more related - it will about enumeration usage. And because of that I decide to make todays examples little bit invalid, not because of structure, everything works perfectly fine, but there is something wrong with concept. Maybe you know what? Is it something about methods? Attributes? Or deciding for enums at all?

I'm waiting for your comments. Answers will come soon :)

No comments:

Post a Comment