Enumeration Pattern – Pt II

Last month I had the good fortune of attending the DDD immersion course lead by Eric Evans. The opening gambit had nothing to do with computers, we looked at a map. A map that did not represent the world geographically, much like the London tube map. Why? To understand modelling. A model exists to express something in a particular context. It is not necessary, or perhaps even possible, to create a model that represents it’s subject through every perspective. The tube map is a model of the underground network that enables commuters to navigate terminals, and it does this flawlessly. Try using the tube map to work out how far away Cockfosters is from Woodford Green? Forget it, you are barking up the wrong tree .

So, how does any of this relate to Enumeration Pattern – Pt I? The solution put forward in that post includes the concept of degrees. An insightful colleague of mine pointed out that it was superfluous to the requirement and I agreed with him. I could sense that it was not quite right, but now I have revisited the problem domain I fully comprehend my mistake; I allowed my understanding of orientation to influence the model and in so doing I added the concept of degrees which was completely unnecessary in order to satisfy the requirement and added complexity that didn’t need to be there.

Here is my latest solution:


public class Orientation
{
    public static readonly Orientation North =  new Orientation("N", 0);
    public static readonly Orientation East = new Orientation("E", 1);
    public static readonly Orientation South = new Orientation("S", 2);
    public static readonly Orientation West = new Orientation("W", 3);

    private static readonly Orientation[] All = new [] { North, East, South, West };

    private readonly string _mnemonic;
    private readonly ushort _sequence;

    protected Orientation(string mnemonic, ushort sequence)
    {
        _mnemonic = mnemonic;
        _sequence = sequence;
    }

    public string Mnemonic
    {
        get { return _mnemonic; }
    }

    public Orientation TurnLeft()
    {
        return All[(_sequence+3) %4];
    }

    public Orientation TurnRight()
    {
        return All[(_sequence + 1) % 4];
    }

    public override string ToString()
    {
        return _mnemonic;
    }

    public static Orientation Parse(string mnemonic)
    {
        if (string.IsNullOrWhiteSpace(mnemonic) || All.All(o => o.Mnemonic != mnemonic.Trim().ToUpper()))
            return null;

        return All.First(o=>o.Mnemonic==mnemonic.Trim().ToUpper());
    }
}

and tests of course;


[TestFixture]
public abstract class OrientationStaticsTests
{
    [Test]
    public void Parse()
    {
        Orientation.Parse("w").Should().Be(Orientation.West);
        Orientation.Parse(" S ").Should().Be(Orientation.South);
        Orientation.Parse(" e").Should().Be(Orientation.East);
        Orientation.Parse(" N  ").Should().Be(Orientation.North);
    }
}

public abstract class OrientationTests
{
    protected abstract Orientation Orientation { get; }
    protected abstract string Mnemonic { get; }
    protected abstract Orientation Left { get; }
    protected abstract Orientation Right { get; }

    [Test]
    public void OrientationValues()
    {
        Orientation.Mnemonic.Should().Be(Mnemonic);
    }

    [Test]
    public void Turn()
    {
        Orientation.TurnLeft().Should().Be(Left);
        Orientation.TurnRight().Should().Be(Right);
    }
}

[TestFixture]
public class NorthOrientationTests : OrientationTests
{
    protected override Orientation Orientation
    {
        get { return Orientation.North; }
    }

    protected override string Mnemonic
    {
        get { return "N"; }
    }

    protected override Orientation Left
    {
        get { return Orientation.West; }
    }

    protected override Orientation Right
    {
        get { return Orientation.East; }
    }
}

[TestFixture]
public class EastOrientationTests : OrientationTests
{
    protected override Orientation Orientation
    {
        get { return Orientation.East; }
    }

    protected override string Mnemonic
    {
        get { return "E"; }
    }

    protected override Orientation Left
    {
        get { return Orientation.North; }
    }

    protected override Orientation Right
    {
        get { return Orientation.South; }
    }
}

[TestFixture]
public class SouthOrientationTests : OrientationTests
{
    protected override Orientation Orientation
    {
        get { return Orientation.South; }
    }

    protected override string Mnemonic
    {
        get { return "S"; }
    }

    protected override Orientation Left
    {
        get { return Orientation.East; }
    }

    protected override Orientation Right
    {
        get { return Orientation.West; }
    }
}

[TestFixture]
public class WestOrientationTests : OrientationTests
{
    protected override Orientation Orientation
    {
        get { return Orientation.West; }
    }

    protected override string Mnemonic
    {
        get { return "W"; }
    }

    protected override Orientation Left
    {
        get { return Orientation.South; }
    }

    protected override Orientation Right
    {
        get { return Orientation.North; }
    }
}

Advertisements

One thought on “Enumeration Pattern – Pt II

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s