2009-05-28

Patterns and Practices - Factory

The Factory (method) Pattern, deals with the problem of creating objects. This is particularly useful when the consumer of the Factory method doesn't care the exact object that's returned, but really only cares that it's of a certain type.

Implementations of the Factory Pattern are often done using interfaces, but it's also not uncommon for them to be done using Abstract (or parent) classes [which may start to broach on the concept of the Abstract Factory Pattern], as well. If you're not familiar with either of these concepts in the .NET world, it's worth your time to do some research--before you continue reading.

The following examples (again, in C#) are just one possible implementation, but they should  help you to understand what to expect when someone discusses the factory patterns.

The following is one of the most basic examples of the factory pattern:

  public interface ICar
  {
    public int CalculateMaxSpeed();
  }

  public class Corvette : ICar
  {
    public Corvette() {}
    public int CalculateMaxSpeed()
    {
      // Of course, you could calculate, coefficients of friction, aerodynamics,
      // torque, gear ratios, blah blah blah. Or just return 180.
      return 180;
    }
  }

  public class StationWagon : ICar
  {
    public StationWagon() {}
    public int CalculateMaxSpeed()
    {
      // Of course, you could calculate, coefficients of friction, aerodynamics,
      // torque, gear ratios, blah blah blah. Or just return 65.
      return 65;
    }
  }

  public class CarFactory
  {
    public static ICar GetCarFactoryMethod(bool DoesCustomerWantSportsCar)
    {
      if (DoesCustomerWantSportsCar)
      {
        return new Corvette();
      }
      else
      {
        return new StationWagon();
      }
    }
  }

Now, to explain what's going on above. First off--we've defined an Interface, ICar. ICar has one method, CalculateMaxSpeed. You'll then notice that there are two implementations for this interface--Corvette and StationWagon. You'll also notice that Corvette and StationWagon have two very different results for CalculateMaxSpeed. Now, if you're writing code to consume this, you'll use CarFactory.GetCarFactoryMethod(bool) to return a car.

Think of it this way--you're a Customer who's shopping for a new Car. You know that you want a sports car, but you don't really care about anything past that. So you go to the CarFactory and ask for a car. It asks you DoesCustomerWantSportsCar, and you reply yes! And viola. CarFactory gives you a Corvette.

To consume this, you'll write code that looks something like this:

public int GetCarsMaxSpeed()
{
  ICar car = CarFactory.GetCarFactoryMethod(checkboxWantSportsCar.Checked);
  return car.CalculateMaxSpeed();
}

Bam. Your CarFactory has returned to you the car that you desire. Of course, you could add in configuration file scanning logic. Perhaps you want to use to facilitate your connections to your database. There's a lot of very intriguing things that you can do with this pattern, so use your imagination!

Oh, also note that some variations of the Factory pattern are more strict--requiring constructors to be private and using having a class implement it's own tightly contained factory method... such as follows:

  public interface ICar
  {
    public int CalculateMaxSpeed();
  }

  public class Corvette : ICar
  {
    private Corvette() {}
    public static ICar GetFastCar(int SomeCriteria)
    {
      // This static method is also a Factory method.
      return new Corvette();
    }
    public int CalculateMaxSpeed()
    {
      // Of course, you could calculate, coefficients of friction, aerodynamics,
      // torque, gear ratios, blah blah blah. Or just return 180.
      return 180;
    }
  }

  public class CarFactory
  {
    public static ICar GetCarFactoryMethod(bool DoesCustomerWantSportsCar)
    {
      if (DoesCustomerWantSportsCar)
      {
        return new Corvette.GetCar();
      }
    }
  }

Practical reasons to use it...

  • You have a multiple different-but-similarly-structured objects that you need to consume at runtime, and they're use may vary at runtime.
  • You want to use some KPI (Key Performance Indicator) to determine which object you want to work with depending on the state of your application.
  • You want to control how your objects are instantiated--as described in the Corvette.GetFastCar above. This also leads to very descriptive instantiations, rather than complex overloads of constructors.

Places where I've used it...

  • An application that used both online / offline data storage. Depending on the availability of an internet connection, it may try to write to a local XML Structure--or to a SQL Server database.

What to be worried about...

  • Are you pushing too much into a factory? Do you really need to determine at runtime what object type you need? Or can you do that during development?
  • There is a minor performance hit by using a separate subroutine instantiate your object and pass it to you. High performance apps may care.
  • Adds complexity to your code and may make debugging more difficult.

More Patterns coming soon. Zoidberg away!

1 comment:

Mina Samy said...

Great information, Thanks