Download C# Source Code |
| Chris Falter recently a submitted great article on refactoring called Refactoring with the Parameterized Factory Pattern. If you haven't read this or are not familiar with refactoring, I'd suggest that you read it before reading this one. Today, I'd like to expand upon his article and demonstrate a real world implementation of this concept. |
| Recently, I had a requirement to put together a website that deals with taking somewhat elaborate financial surveys. While the questions and answers themselves are good candidates for being database driven, there were a large number of nuiances ranging from UI items, business rules, and calculations that just didn't fit into a database driven strategy. With this in mind, my initial strategy was to create version specific classes and reference them in version specific ASP.NET pages. Of course, this accomplished the initial requirement. However, whenever a new version needs to be implemented, I had to copy all of the ASP.NET pages and modify the references to the appropriate version specific class name. Refactoring provides a better alternative and here's how: |
| Using the Parameterized Factory Pattern, we can create a VersionFactory class that returns back a version specific class based on the version type or id passed into the VersionFactory. Not only can we dynamically return a specific class, we can also move methods back and forth between the version specific classes and the VersionMain class without adjusting anything in our ASP.NET pages or outside classes. This enables us to create a default class to handle all standard versions and custom classes for those versions with special business rules while the UI section of our code is obvilious. We don't have store any information in the database stating whether it is a custom class or not. If the custom class simply exists, it is used. Otherwise, the default class is returned. The following is a graphical representation of our class diagram: |
 |
|
|
| The sample code below demonstrates how to override items in VersionMain where necessary. An important item to remember is that any method, property, etc. that is defined in a version specific class must also have an item placed in the public IVersion interface. Items in the inherited VersionMain class do not have to be referenced in the IVersion interface. |
|
| Class1.cs |
using System;
namespace Refactor
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Class1 oClass = new Class1();
oClass.Test();
Console.ReadLine();
}
public void Test()
{
IVersion oVersion;
Refactor.Session oSession = new Refactor.Session();
oSession.VersionID = 1;
oVersion = Refactor.VersionFactory.GetClass(oSession.VersionID);
Console.WriteLine(oVersion.Name);
Console.WriteLine(oVersion.Text);
oSession.VersionID = 2;
oVersion = Refactor.VersionFactory.GetClass(oSession.VersionID);
Console.WriteLine(oVersion.Name);
Console.WriteLine(oVersion.Text);
oSession.VersionID = 3; // Default class is returned
oVersion = Refactor.VersionFactory.GetClass(oSession.VersionID);
Console.WriteLine(oVersion.Name);
Console.WriteLine(oVersion.Text);
}
}
}
|
| VersionFactory.cs |
using System;
namespace Refactor
{
public interface IVersion
{
string Name
{
get;
}
string Text
{
get;
}
}
public class VersionFactory
{
public static IVersion GetClass(int VersionID)
{
switch(VersionID)
{
case 1:
return new Refactor.Version1();
case 2:
return new Refactor.Version2();
default:
return new Refactor.VersionDefault();
// or return a default class here
}
}
}
}
|
| Version1.cs |
using System;
namespace Refactor
{
public class Version1: Refactor.VersionMain, Refactor.IVersion
{
public string Name
{
get
{
return "Version 1";
}
}
public override string Text
{
get
{
return "Text override";
}
}
}
}
|
| Version2.cs |
using System;
namespace Refactor
{
public class Version2: Refactor.VersionMain, Refactor.IVersion
{
public string Name
{
get
{
return "Version 2";
}
}
}
}
|
| VersionDefault.cs |
using System;
namespace Refactor
{
public class VersionDefault: Refactor.VersionMain, Refactor.IVersion
{
public string Name
{
get
{
return "Default Version";
}
}
}
}
|
| VersionMain.cs |
using System;
namespace Refactor
{
public class VersionMain
{
public VersionMain() { }
public virtual string Text
{
get
{
return "Main Text";
}
}
}
}
|
| Session.cs |
using System;
namespace Refactor
{
public class Session
{
public int VersionID = 1;
public Session() { }
}
}
|