C# Coding Solutions—Classical Factory Pattern

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio


Jump to: navigation, search
CSharp-Online.NET:Articles
C# Articles

C# Coding Solutions

© 2006 Christian Gross

The Classical Factory Pattern

Consider the following source code that illustrates the code written without using a Factory pattern:

public class UseItDirectly {
    public void Method() {
        Console.WriteLine( "I will be called directly");
    }
}
// ...
UseItDirectly cls = new UseItDirectly();
cls.Method();

In the example the class UseItDirectly has a single method, Method. To call Method the class UseItDirectly is instantiated. The code works and is simple, but maintaining and extending the code is complicated. Imagine if UseItDirectly were a version 1.0 class, and that for the next version the class is used by other classes and methods, as illustrated in the following example:

public class UseItDirectly {
    public void Method() {
        Console.WriteLine
           ( "I will be called directly (with bugfix)");
    }
}
 
public class NewClassIntroduced {
    public void Method() {
        UseItDirectly cls = new UseItDirectly();
        cls.Method();
    }
}
// ...
UseItDirectly cls = new UseItDirectly();
cls.Method();
 
NewClassIntroduced cls2 = new NewClassIntroduced();
cls2.Method();

In the example NewClassIntroduced has a method Method that calls UseItDirectly. The old code that instantiates the class UseItDirectly still exists, but now additional code instantiates and calls UseItDirectly directly. During operations, NewClassIntroduced realizes that there is a bug in UseItDirectly. The bug causes NewClassIntroduced to work improperly, and the bug needs fixing. For illustration purposes the Console.WriteLine has been updated to reflect that UseItDirectly has been updated to fix a bug.

It seems everything is correct and the source code using the two classes should work properly. But in fact a new bug has been created, as illustrated by executing the code and looking at the generated output:

I will be called directly (with bugfix)
I will be called directly (with bugfix)

The two lines of generated output are identical, and that indicates a bug. You may think the output is identical because UseItDirectly has a fixed bug. The problem is that the old code that was working has the fixed bug as well. Maybe the old code did not want the bug fix, or maybe the coder assumed the bug was normal and compensated. The reality is that the system was buggy because of NewClassIntroduced, not because of version 1.0. This means that all of the old working code has to be retested and potentially fixed to adjust for the bug. When fixing bugs, be careful what you fix!

Using classes directly does not promote separation and modularization of code. You tend to write big lumps of code, which is one of the many reasons why you should not use classes directly. Instead you want to use component-driven development that involves using an interface and a class that implements an interface or a base class. The following example illustrates how to create a component:

interface InterfaceToBeShared  { }
class ImplementsInterface : InterfaceToBeShared { }
// ...
InterfaceToBeShared inst = new ImplementsInterface();

The interface InterfaceToBeShared is a base type that all consumers use. In the example the interface has no methods, but that is only for illustration purposes. The interface defines your intent. The class ImplementsInterface implements InterfaceToBeShared and is called an implementation of the intention. A consumer could use the interface instance by instantiating the class ImplementsInterface. Instantiating the class and then assigning the instance to a variable referencing an interface is wrong. To instantiate the class ImplementsInterface you need to know about the class, and in .NET-speak that means having access to the type information. Yet that is what we want to avoid because we don’t want instantiate a type directly. We would like to delegate the call to some other piece of functionality.

To be able to create an instance of an interface or abstract class using patterns, you use the Factory pattern. The Factory pattern says that instead of you instantiating an object directly, another class will do that for you. This lets the class that does the indirect instantiation figure out what type you want or need. In the simplest case the indirect instantiation would appear similar to the following:

public interface InterfaceToBeShared  { }
class ImplementsInterface : InterfaceToBeShared { }
public class Factory {
    public static InterfaceToBeShared CreateObject() {
        return new ImplementsInterface ();
    }
}

In the example the class Factory has a static method CreateObject that instantiates the type ImplementsInterface but returns an InterfaceToBeShared interface instance. Notice the strategic use of the public keyword in the code example. The interface and factory were declared public, but the implementation was not. This means that anybody who uses the factory and interface does not need to know how the interface is implemented. The importance of this will become apparent shortly. To use the factory you could write the following code:

InterfaceToBeShared interf = Factory.CreateObject();
interf.SomeMethod();

The consumer of InterfaceToBeShared would call the method Factory.CreateObject that returns a manipulatable interface instance. The delegation of functionality has worked, and the implementation of Factory.CreateObject can decide how it wants to instantiate an interface instance. The consumer needs to know only about the factory and the interface.

The Factory pattern does enable a developer to write code that can be extended and maintained and is generally more flexible than writing code that accesses the classes directly. The downside is that the Factory pattern can complicate things, as illustrated by the following example that fixes the class that had one of its bugs fixed. The following solution shows that no matter how ugly things get underneath, the consumer is blissfully ignorant of the implementation:

public interface IUseIt {
    void Method();
}
class UseItDirectly : IUseIt {
    public void Method() {
        Console.WriteLine("I will be called directly");
    }
}
 
class UseItDirectlyFixed : IUseIt {
    public void Method() {
        Console.WriteLine("I will be called directly (with bugfix)");
    }
}
 
class NewClassIntroduced : IUseIt {
    public void Method() {
        UseItDirectlyFixed cls = new UseItDirectlyFixed();
        cls.Method();
    }
}
 
public class Factory {
    public static IUseIt Version1() {
        return new UseItDirectly();
    }
    public static IUseIt Version2() {
        return new NewClassIntroduced();
    }
}
// ...
IUseIt cls = Factory.Version1();
cls.Method();
 
IUseIt cls2 = Factory.Version2();
cls2.Method();

In the solution, the class Factory has two methods: Version1 and Version2. Version1 instantiates the type UseItDirectly. Version2 instantiates the type NewClassIntroduced, which itself instantiates the type UseItDirectlyFixed. The type UseItDirectlyFixed is a copied-and-pasted version of UseItDirectly that contains the bug fixes needed for NewClassIntroduced.

In general, a copy and paste is extremely bad programming practice. But in this instance a developer pressed for time can say, "But the changes are contained in a single assembly and nobody will ever see the problems. We can fix the code later." The fact that no external assembly sees the problem is a not a carte blanche for bad programming practices. The example code illustrates that no matter the mess behind the Factory pattern and interface, the client is blissfully unaware. If at a later point the code is fixed and a refactoring were undertaken, then the consumer would still be blissfully unaware. This is the point of component-driven development and the reason why a factory is necessary. The code has been modularized and all that matters is the implementation of the interface contract.

At the beginning of this solution I said that the Factory pattern is technically more complex. I still stand by that assertion. But what I also want to point out is that because you only write a Factory once and modify it very rarely, your code becomes simpler because you don’t have to do coding contortions when maintaining and bug-fixing code.


Previous_Page_.gif Next_Page_.gif


Personal tools