I’ve got a beef with enums. When I see them, I cringe… which is quite different from my days in C, where I couldn’t live without enums and structs. That’s another story…

“Flyweight: Use sharing to support large numbers of fine-grained objects efficiently” - Design Patterns

Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series) by Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
Read more about this title…

Why do some of us quickly jump to enums? In procedural languages it makes sense. It’s giving a type code a human readable meaning. So instead of having to stare at type code 1, everywhere you can use State.Acknowledgement, which is a lot easier to understand … what does 1 mean again?

But in an OO language, I feel dirty when I see enums. The argument of using it for bitwise operations and the Flags attribute is weak. Create a composite!

[Flags]
  public enum Digits {
      Zero = 0x00,
      One = 0x01,
      Two = 0x02,
      Three = 0x03,
      Four = 0x04,
      Five = 0x05,
      Six = 0x06,
      Seven = 0x07,
      Eight = 0x08,
      Nine = 0x09
  }

  [Test]
  public void Should_be_equal_to_2_digits() {
      Digits digits = Digits.Six | Digits.One;
      Assert.IsTrue( Digits.Six == (digits & Digits.Six) );
      Assert.IsTrue( Digits.One == (digits & Digits.One) );            
  }

Weak… do you really want to use a bitwise & to check if a certain digit is enabled. I don’t. I’m going to use the following 2 tests to squash the enum into a first class component, with some smarts to it.

[Test]
  public void should_be_able_to_add_a_single_digit() {
      INumberBuilder builder = CreateSUT( );
      builder.Add( Digits.One );
      Assert.AreEqual( new Number( 1 ), builder.Build( ) );
  }

  [Test]
  public void should_be_able_to_form_a_number_with_more_than_one_digit() {
      INumberBuilder builder = CreateSUT( );
      builder.Add( Digits.One );
      builder.Add( Digits.Nine );
      Assert.AreEqual( new Number( 19 ), builder.Build( ) );
  }

My current NumberBuilder implementation looks like this (it sucks but it works):

public class NumberBuilder : INumberBuilder {
      public void Add( Digits digit ) {
          numberBeingBuilt += Convert.ToString( Convert.ToInt32( digit ) );
      }

      public INumber Build() {
          return new Number( Convert.ToInt32( numberBeingBuilt ) );
      }

      private string numberBeingBuilt;
  }

I’m going to start off by creating some Flyweights.

public class Digits {
      public static readonly IDigit Eight = new Digit( 8 );
      public static readonly IDigit Five = new Digit( 5 );
      public static readonly IDigit Four = new Digit( 4 );
      public static readonly IDigit Nine = new Digit( 9 );
      public static readonly IDigit One = new Digit( 1 );
      public static readonly IDigit Seven = new Digit( 7 );
      public static readonly IDigit Six = new Digit( 6 );
      public static readonly IDigit Three = new Digit( 3 );
      public static readonly IDigit Two = new Digit( 2 );
      public static readonly IDigit Zero = new Digit( 0 );

      public class Digit : IDigit {
          public Digit( int digitToRepresent ) {
              _digitToRepresent = digitToRepresent;
          }

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

          private readonly int _digitToRepresent;
      }
  }

My compiler is telling me that the Add method on my builder currently accepts a parameter of type “Digits”, so I’m going to change the signature to accept a parameter of type IDigit.

public interface INumberBuilder {
      void Add( Digits digit );
      INumber Build();
  }

To…

public interface INumberBuilder {
      void Add( IDigit digit );
      INumber Build();
  }

Let’s update the NumberBuilder implementation to:

public class NumberBuilder : INumberBuilder {
      public NumberBuilder() {
          _digitsOfNumberBeingBuilt = new List< IDigit >( );
      }

      public void Add( IDigit digit ) {
          _digitsOfNumberBeingBuilt.Add( digit );
      }

      public INumber Build() {
          return new Number( CreateIntegerFrom( _digitsOfNumberBeingBuilt ) );
      }

      private int CreateIntegerFrom( IEnumerable< IDigit > digitsOfNumberBeingBuilt ) {
          StringBuilder builder = new StringBuilder( );
          foreach ( IDigit digit in digitsOfNumberBeingBuilt ) {
              builder.Append( digit );
          }
          return Convert.ToInt32( builder.ToString( ) );
      }

      private IList< IDigit > _digitsOfNumberBeingBuilt;
  }

I run the tests and they pass, sweet. But I’m not happy with the current implementation, so I look for other potential refactorings. I decide to forward the digit to append right to the number, the number can take care of how to append the digit, rather then having the builder doing so. The builder now looks like:

public class NumberBuilder : INumberBuilder {
      public NumberBuilder() {
          _numberBeingBuilt = new Number( 0 );
      }

      public void Append( IDigit digit ) {
          _numberBeingBuilt = _numberBeingBuilt.Append( digit );
      }

      public INumber Build() {
          return _numberBeingBuilt;
      }

      private INumber _numberBeingBuilt;
  }

And Number looks like:

public class Number : INumber, IEquatable< Number > {
      public Number() : this( 0 ) {}

      public Number( int numberToRepresent ) {
          _numberToRepresent = numberToRepresent;
      }

      public INumber Append( IDigit digit ) {
          return new Number( ( _numberToRepresent*10 ) + digit.Value( ) );
      }

      public bool Equals( Number number ) {
          if ( number == null ) {
              return false;
          }
          return _numberToRepresent == number._numberToRepresent;
      }

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

      public override bool Equals( object obj ) {
          if ( ReferenceEquals( this, obj ) ) {
              return true;
          }
          return Equals( obj as Number );
      }

      public override int GetHashCode() {
          return _numberToRepresent;
      }

      private readonly int _numberToRepresent;
  }

To wrap this up, Number aggregates digits, the enum got dropped and was replaced by a class. There’s still more refactorings that can occur, but the point is that a full blown component is much easier to extend then an enum…

For more info check out “Replace Type Code with Class” from…

Refactoring: Improving the Design of Existing Code (The Addison-Wesley Object Technology Series) by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts

Read more about this title…

comments powered by Disqus