Friday, October 1, 2010

Abstract Factory Pattern In C#.Net

Sometimes when building and application you need to plan for changes that you cannot possibly plan for. For example, if you are building an application to import data from different sources and you will receive that data in completely different formats one, approach might be to create a different application for each import. That's a valid approach, but one that requires a good deal of code duplication. Let us examine the Abstract Factory pattern and see how it might help us here.

Both the old classic Design Patterns (Gamma, Helm, Johnson and Vlissides) and the new classic Head First Design Patterns from O'Reilly (Freeman and Freeman) define the Abstract Factory pattern as a way to "Provide an interface for creating families of related or dependent objects without specifying their concrete classes. " What does that actually mean? In the example business problem from above, we could create a class for each import type that implements an interface, therefore decoupling the import parsing from the persistence of the data. In other words, we don't have to write a new application for each import type, just a new class.

The first thing I will do is create a new project and then add an Enum named ParsableType and an Interface named IImportParsable.

public class ParsableTypes
{
public enum ParsableType
{
Excel = 1,
FixedFormat = 2
}
}

public interface IImportParsable
{
bool Parse();
}

Next, I will create 2 new classes that implement our interface...

public class ExcelParser : IImportParsable
{
public bool Parse()
{
//do some excel parsing here
return true;
}
}

public class FixedFormatParser : IImportParsable
{
public bool Parse()
{
//do some text file parsing here
return true;
}
}

Next, we need a factory to determine which parser to use...
public class ImportParsableFactory
{
public static IImportParsable GetImportParser(ParsableTypes.ParsableType parsableType)
{
IImportParsable importParsable = null;

switch (parsableType)
{
case ParsableTypes.ParsableType.Excel :
importParsable = new ExcelParser();
break;

case ParsableTypes.ParsableType.FixedFormat :
importParsable = new FixedFormatParser();
break;
}

return importParsable;
}
}

Finally, we just need a controller to get the parse type and then call the parse method...
public void Import(int parseID)
{
IImportParsable importParser = ImportParsableFactory.GetImportParser((ParsableTypes.ParsableType)parseID);
importParser.Parse();
}
}

As new parse needs arise, we just add an enum entry, create a new class that implements IImportParsable and add another case to our switch and we are done. We have a nice decoupled approach that we can use by itself or combine with the Facade or Decorator patterns to add even more pattern goodness.

No comments:

Post a Comment