Thursday, 10 July 2014

Factory methods within a class can access private members.

There are times when I want to hide construction details and provide a factory method within the class to create objects.

I've found it handy for dependency injection, test classes, etc

Here's one of the patterns I've been using:



namespace Blog.Articles
{
  /// <summary>Use this class if you want a 'vanilla' implementation.</summary>
  public class ClassWithFactoryMethods : BaseClassWithFactoryMethods<ClassWithFactoryMethods>
  {
  }

  /// <summary>Demonstrate the implementation of a factory method which allows for sub-classing.</summary>
  /// <typeparam name="TSelf">The type of the class being. </typeparam>
  public class BaseClassWithFactoryMethods<TSelf> where TSelf : BaseClassWithFactoryMethods<TSelf>new()
  {
    /// <summary>
    /// This the factory method which is responsible for creating objects of <typeparamref name="TSelf"/>.
    /// </summary>
    /// <param name="param">An example parameter.</param>
    /// <returns>Returns an object of the requested sub-type.</returns>
    public static TSelf CreateOne(string param)
    {
      //// do some work before constructing the object using a private constructor

      //// ...

      // all the pre-requisites are satisfied so it's about time to construct ourselves one of these
      // using the public default contructor (which gives inheritors the change to do specialist work)
      var result = new TSelf();

      //// call any private initialisation methods

      // do some 'work'
      var otherParam = param.ToLower();

      // we can call private methods on this class in here where a 'normal' factory method could not
      result.Initialise(otherParam);

      return result;
    }

    /// <summary>Show how the factory method can call the object's private methods.</summary>
    /// <param name="exampleParam">Example parameter.</param>
    private void Initialise(string exampleParam)
    {
      // do some object initialisation
    }
  }

  ////////////////////////////////////////////////////////////////
  //// Example of using the class with its internal factory and
  //// how to return sub-classes of it
  ////////////////////////////////////////////////////////////////

  /// <summary>Show how to use these static methods.</summary>
  public static class TestClassWithFactoryMethods
  {
    /// <summary>Show how to create objects using the factory method.</summary>
    public static void CreateOne()
    {
      // create a 'standard' ClassWithFactoryMethods object 
      ClassWithFactoryMethods one = ClassWithFactoryMethods.CreateOne("Foo");

      // create another using the same method, but returning a derived object type
      MyClassWithFactoryMethods another = MyClassWithFactoryMethods.CreateOne("Foo");

      // we can now call methods on the sub-class
      another.ExtendedMethod();
    }

    /// <summary>Define a sub-class to show how the static method now returns the correct flavor of class.</summary>
    public class MyClassWithFactoryMethods : BaseClassWithFactoryMethods<MyClassWithFactoryMethods>
    {
      /// <summary>Extend the base as required.</summary>
      public void ExtendedMethod()
      {
      }
    }
  }
}

No comments: