Enumeration Pattern

UPDATE: I have since followed up this post with Enumeration Pattern – Pt II

In this post I want to discuss a pattern that I use regularly; Enumeration. I won’t claim this pattern as my own because it’s a fairly obvious pattern and I expect (although I have not researched) many people have come up the same or very similar pattern long before me, but I will describe in detail how I implement it in C# and why it is better than using vanilla C# enums.

The Problem

Even the newest of C# noob knows about enums, right?

public enum Orientation
{
    North,
    South
}

Handy, so now I can write conditional logic using Orientation, e.g.:

public void Foo(Orientation orientation)
{
    switch (orientation)
    {
        case Orientation.North:
            ...
            break;
        case Orientation.South:
            ...
             break;
    }
}

There is more to be said about enums, such as the static methods on the base class, use of flags, integer mapping etc., but that isn’t the point of this post as none of these things help with the problem I will go on describe.

What I don’t like about enums is that they are static; you can’t extend their behaviour via inheritance. In fact they have no behaviour and wherever there are enums invariably there is conditional logic. Switch statements and if..else blocks are often the enemy of extensibility and in this case encapsulation. For example, if I build a system that makes extensive use of the above enum and I now want to support NorthEast, SouthEast, SouthWest and NorthWest I have to revisit every conditional block that references Orientation. This is not the fertile promised land of OO <milkAndHoney/>, this is procedural wasteland <tumbleweed/>.

“Wait! you forgot extension methods” I hear you say.  No, I did not. Yes, you can use extension methods to extend enums and rid yourself of all those conditional blocks in the client code, but extension methods are no panacea.  A full discussion of the pros and cons of extension methods is beyond the scope of this post, but sufficed you say that with regard to enums this approach only moves the problem, it doesn’t solve it. There will still be lots of conditional logic, albeit in one place and there will be lots of extrinsic data kicking around that should be intrinsic to the enum. There are other problems too such as you can’t override extension methods and you can’t mock enums (ok, there would be no point even if you could as they have no instance members, but you see where I am going with this)

What I do like about enums is that they are:

  • Immutable
  • Referenced statically (i.e. Direction.North so no need to instantiate anything explicitly)

So how can we get the best of both worlds?

The Solution

Below are two subtly different implementations of the enumeration pattern which are equivalent to the above with some bells and whistles to demonstrate the power of this pattern over plain enums.

using System.Collections.Generic;
using System.Linq;

namespace EnumerationPattern
{
    public interface IOrientation
    {
        string Name { get; }
        Degrees Degrees { get; }
    }

    public abstract class Orientation : IOrientation
    {
        public static readonly IOrientation North = new NorthOrientation();
        public static readonly IOrientation South = new SouthOrientation();

        public static readonly IEnumerable All = new[]
        {
            North, South
        };

        public IOrientation Parse(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            name = name.ToLower().Trim();

            return All.FirstOrDefault(
                o =&gt; o.Name.ToLower().Trim().Equals(name));
        }

        private readonly string _name;
        private readonly Degrees _degrees;

        protected Orientation(string name, Degrees degrees)
        {
            _name = name;
            _degrees = degrees;
        }

        public Degrees Degrees
        {
            get { return _degrees; }
        }

        public string Name
        {
            get { return _name; }
        }

        public override string ToString()
        {
            return Name;
        }

        private class NorthOrientation : Orientation
        {
            public NorthOrientation()
                : base(&quot;North&quot;, Degrees.Zero) {}
        }

        private class SouthOrientation : Orientation
        {
            public SouthOrientation()
                : base(&quot;South&quot;, Degrees.OneHundredEighty) {}
        }
    }

    public struct Degrees
    {
        public static readonly Degrees Zero = new Degrees(0);
        public static readonly Degrees OneHundredEighty = new Degrees(180);

        public static readonly Degrees[] All =
        {
            Zero,
            OneHundredEighty,
        };

        private readonly uint _value;

        private Degrees(uint value)
        {
            _value = value;
        }

        public static Degrees operator+(Degrees left, Degrees right)
        {
            var newValue = left._value + right._value;

            newValue = (newValue &lt; 360) ? newValue : newValue - 360;
            return All.First(d =&gt; d._value == newValue);
        }

        public static Degrees operator -(Degrees left, Degrees right)
        {
            var leftValue = (right._value &gt; left._value)
                                ? left._value + 360
                                : left._value;

            var newValue = leftValue - right._value;

            return All.First(d =&gt; d._value == newValue);
        }

        public static bool operator ==(Degrees left, Degrees right)
        {
            return left._value == right._value;
        }

        public static bool operator !=(Degrees left, Degrees right)
        {
            return left._value != right._value;
        }

        public override int GetHashCode()
        {
            return &quot;Degrees&quot;.GetHashCode() + _value.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is Degrees)
                return this == (Degrees) obj;

            return false;
        }

        public override string ToString()
        {
            return _value.ToString();
        }
    }
}

Now we can use inheritance, we can introduce private state and we can define instance members to our hearts content.  We also have an IOrientation interface which is invaluable when it comes to mocking for TDD whilst maintaining immutability and static referencing as is the case with an enum.

Advertisements

3 thoughts on “Enumeration Pattern

  1. @Ashter Thanks. That is a good point. Just looking at the above code the answer is no. Degrees does not have to be an enumeration and could simply have a public constructor (with some logic to deal with values outside of 0-359). When I have some free time I might write up another post + solution that implements this.

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