Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Factory Method Pattern using Partial & Nested classes in C#

0.00/5 (No votes)
17 Apr 2016 1  
This article helps in learning how to apply C# concepts like Nested classes and Partial classes to implement Factory Method pattern.

Introduction

The objective of this article is to learn how to apply C# concepts like Nested classes and Partial classes to implement Factory Method pattern. This article will briefly show what Factory Method pattern is and what problems it solves but will focus primarily on how we can use Nested & Partial classes to achieve better abstraction. If you are already familiar with Factory Method Pattern you can directly jump to the "Better Abstraction" section.

Background

Factory Method pattern deal with the problem of managing object creation. It let the client use the objects without having to worry about how those objects are created. When some client code needs to use some functionality from a class, it first need to get an instance of that class and then only it can use the functionality. Now creation of objects may not be that simple all the times, in most of cases certain initializations need to be done before/after an object is created. If all this logic to create and initialize the object is left with client code it may require changing client code in future if any of the creation or initialization approach needs to be changed.

Now consider a more complex scenario where you have a family of classes and your client needs to decide at runtime which object will be used, so if your client is responsible for creating the actual object at runtime based on some information, it will have to be changed every time a new type is added to the family. This will become very complicated if you have a lot of types in family and more can be added later. Let’s try to understand this problem with an example:

Assume we have an application which generates and prints different kind of documents for example: an Excel document, Word document etc. Client wants to use “Print” functionality of these documents. Now to create a family of documents in our C# code we can have an abstract base class for "Document" as follows:

public enum DocumentType { None, PDF, Word, Excel, PowerPoint }
public abstract class Documen
{
        public string Name { getset; }
        public abstract DocumentType Type { get; }
        public abstract string Print();
}

And two different implementations of this abstraction

class ExcelDocument : Document
    {
        public override DocumentType Type
        {
            get
            {
                return DocumentType.Excel;
            }
        }

        public override string Print()
        {
            return "Excel";
        }
    }

And

class WordDocument : Document
    {
        public override DocumentType Type
        {
            get
            {
                return DocumentType.Word;
            }
        }
        public override string Print()
        {
            return "Word";
        }
    }

client code will looks like this:

static void Main(string[] args)
        {
            Document document = new NullDocument();
            DocumentType documentType;
            string type = Console.ReadLine();            

            if (Enum.TryParse<DocumentType>(type, out documentType))
            {
                switch (documentType)
                {
                    case DocumentType.Excel:
                        document = new ExcelDocument() { Name = "Excel" };
                        break;
                    case DocumentType.Word:
                        document = new WordDocument() { Name = "Word" };
                        break;
                    case DocumentType.PowerPoint:
                        document = new PowerPointDocument() { Name = "PowerPoint" };
                        break;
                    case DocumentType.PDF:
                        document = new PDFDocument() { Name = "PDF" };
                        break;
                    default:
                        document = new NullDocument();
                        break;
                }
            }
            else
            {
                Console.WriteLine("Invalid Input.");
            }

            Console.WriteLine("Printing {0} document", document.Print());

            Console.ReadKey();
        }

All of the above code is very straightforward, client code takes input from user and creates the appropriate instance of "Document" and performs the required operations.

Now If Its needed to add a third type to hierarchy called “PowerPoint” or “PDF”, we will end up writing two new implementations of Document for “PDF” and “PowerPoint” and modify client to insert proper "switch"-“case” statements to handle creation of these two new types. So client code is tightly coupled with implementation classes and what it means is that our code is breaking “Dependency Inversion Principle” which states that "higher level modules (client code) should not depend on lower level modules (classes implementing logic for various types PDF, Excel etc.), both should depend on abstraction (abstract “Document”). So looking at this code as of now we see few problems:

  1. Client depends on concrete class rather than just abstraction.
  2. Client is doing additional work of creating objects which requires it to be changed every time a new type is added to hierarchy or way to initialize objects is changed.

Answer to all of these problems is "Factory Method Pattern", all we need to do is to separate the creation of object. We will introduce another class called “DocumentFactory” which will have sole responsibility of creating objects to be used by clients and every time a client needs a particular type of object it will ask the Factory to create one for it. Let’s have a look at the code.

We will introduce one "Factory" class:

public class DocumentFactory
        {
            public Document CreateDocument(DocumentType documentType)
            {
                switch (documentType)
                {
                    case DocumentType.Excel: return new ExcelDocument() { Name = "Excel Document" };
                    case DocumentType.PDF: return new PDFDocument() { Name = "PDF Document" };
                    case DocumentType.PowerPoint: return new PowerPointDocument() { Name = "PowerPoint Document" };
                    case DocumentType.Word: return new WordDocument() { Name = "Word Document" };
                    defaultreturn new NullDocument() { Name = "" };
                }
            }
        }

Now based on what type is asked, this Factory will create the object, initialize it properly and return to the client.

Note that the return value of “CreateDocument()” method is “Document” so client only need to know the abstracted details, client code will look like as follows:

static void Main(string[] args)
        {
            DocumentFactory documentFactory = new DocumentFactory();
            Document document = new NullDocument();
            DocumentType documentType;
            string type = Console.ReadLine();
            if (Enum.TryParse<DocumentType>(type, out documentType))
            {
                document = documentFactory.CreateDocument(documentType);
            }
            else
            {
                Console.WriteLine("Invalid Input.");
            }
            Console.WriteLine("Printing {0} document", document.Print());
            Console.ReadKey();
        }

Now we can add any number of types to the hierarchy, client code will never need to change. This is standard implementation of "Factory Method Pattern" in C#, but there are still certain problems with this design, let’s have a look again and try to figure out what else might not be very good with this design (found anything?)

 

Better Abstraction

Client code only needs to know about abstract "Document" right? It should not depend on lower level details just the abstraction, but what if I try to do the following in my code:

Document doc = new ExcelDocument();

What’s stopping us from doing this? Nothing. What if tomorrow a new developer joins the team or someone who is using the library try to use this code and end up using the above code, how is it made sure the objects are properly initialized before those are used (which is the responsiblity of Factory) and the biggest question is how do we ensure that only Factory can create objects and no body else.

Another problem: Say we want to control how many types of document this library can support. As of now anybody can extend "Document" and provide their own implementations like this:

class MyDocument : Document
    {
        public override DocumentType Type
        {
            get
            {
                return DocumentType.PDF;
            }
        }
        public override string Print()
        {
            throw new NotImplementedException();
        }
    }

and this type will not be created through Factory class, because Factory does not know about this type.

It can create problems and at the very least it does allow me to supply more types than what library offers which is not what we want. So can it be somehow restricted? Thankfully yes we can do this with C# by combining two powerful but least used features of C#

  1. Nested Classes
  2. Partial Classes

In fact this can be done with the help of only Nested classes but Partial classes will help us keep our code clean which we will see soon.

So let’s go back and revisit our problem, we want to achieve separation for "creation and initialization of objects" from the client code. To do so we decided to use a Factory class which will create concrete objects and provide those back to our clients, so what does client needs then? Just the abstraction which is provided by the abstract class "Document" so why expose my concrete types to rest of the world? And, who needs to know about concrete types which implements the abstraction provide by "Document" class, Only the class responsible for actually creating these objects i.e. our Factory class. Now we need to achieve better abstraction by hiding the concrete types from the rest of world and only making those accessible to Factory class.

Nested classes comes to rescue:

public class DocumentFactory
        {
             public override Document CreateDocument(DocumentType documentType)
            {
                switch (documentType)
                {
                    case DocumentType.Excel: return new ExcelDocument() { Name = "Excel Document" };
                    case DocumentType.PDF: return new PDFDocument() { Name = "PDF Document" };
                    case DocumentType.PowerPoint: return new PowerPointDocument() { Name = "PowerPoint Document" };
                    case DocumentType.Word: return new WordDocument() { Name = "Word Document" };
                    defaultreturn new NullDocument() { Name = "" };
                }
            }

            class ExcelDocument : Document
            {
                public override DocumentType Type
                {
                    get
                    {
                        return DocumentType.Excel;
                    }
                }

                public override string Print()
                {
                    return "Excel";
                }
            }
        }

We could make all our concrete types nested to the Factory class that way only Factory class will be able to access the concrete types and instantiate those. Now one of the problems is solved, nobody now can do this:

Document doc = new ExcelDocument();

If you want an instance of a concrete "Document" type, you have to ask Factory, that’s the only way.

About our second problem, anybody can still inherit from "Document" and provide their own implementations well again that can be solved using Nested classes. Nested class has a very unique feature

“Nested classes can access private members of their containing types.” So we can mark the constructor for "Document" class as private which will stop any class from inheriting it as follows:

public class Document
    {
        private Document()
        { 
        }
        public string Name { getset; }
        public abstract DocumentType Type { get; }
        public abstract string Print();
        public class DocumentFactory
        {
            public Document CreateDocument(DocumentType documentType)
            {
                switch (documentType)
                {
                    case DocumentType.Excel: return new ExcelDocument() { Name = "Excel Document" };
                    case DocumentType.PDF: return new PDFDocument() { Name = "PDF Document" };
                    case DocumentType.PowerPoint: return new PowerPointDocument() { Name = "PowerPoint Document" };
                    case DocumentType.Word: return new WordDocument() { Name = "Word Document" };
                    defaultreturn new NullDocument() { Name = "" };
                }
            }
            class ExcelDocument : Document
            {
                public override DocumentType Type
                {
                    get
                    {
                        return DocumentType.Excel;
                    }
                }
                public override string Print()
                {
                    return "Excel";
                }
            }
        }
    }

Now we have an abstract class "Document" with a private constructor which means nobody can implement it other than types nested inside this class. "Document" class contains a Nested class "DocumentFactory" which has one method to create concrete types and again nested classes for each of the concrete types. All of the concrete types are able to inherit from "Document" even though it has a private constructor because of C# Nested class feature allowing nested types to access private members of its containing type, but nobody else can implement "Document" now. So that’s the solution to our second problem.

Now we have an added layer of abstraction with all of the irrelevant details (like concrete implementations, creation of objects etc. is completely hidden from client, it works only on abstraction).

Final simplification I would want with this code is to be able to write my Nested concrete types in separate files because if I end up writing all of the implementation in one file nested under "Document" and the "DocumentFactory" it will be a whole lot of code in one file, so we use Partial classes which will simply allow me to write my code in separate file but still using Nested classes.

Document.cs

public abstract partial class Document
    {
        private Document()
        {
        }
        public string Name { getset; }
        public abstract DocumentType Type { get; }
        public abstract string Print();
        public partial class DocumentFactory
        {
        }
    }

 

DocumentFactory.cs

public partial class Document
    {
        public partial class DocumentFactory
        {
            public override Document CreateDocument(DocumentType documentType)
            {
                switch (documentType)
                {
                    case DocumentType.Excel: return new ExcelDocument() { Name = "Excel Document" };
                    case DocumentType.PDF: return new PDFDocument() { Name = "PDF Document" };
                    case DocumentType.PowerPoint: return new PowerPointDocument() { Name = "PowerPoint Document" };
                    case DocumentType.Word: return new WordDocument() { Name = "Word Document" };
                    defaultreturn new NullDocument() { Name = "" };
                }
            }
        }
    }

 

ExcelDocument.cs

public partial class Document
    {
        public partial class DocumentFactory
        {
            class ExcelDocument : Document
            {
                public override DocumentType Type
                {
                    get
                    {
                        return DocumentType.Excel;
                    }
                }
                public override string Print()
                {
                    return "Excel";
                }
            }
        }
    }

WordDocument.cs

public partial class Document
    {
        public partial class DocumentFactory
        {
            class WordDocument : Document
            {
                public override DocumentType Type
                {
                    get
                    {
                        return DocumentType.Word;
                    }
                }
                public override string Print()
                {
                    return "Word";
                }
            }
        }
    }

And as many more as you need, clean enough?

Summary

Factory Method pattern allows separation of creation of objects from client code, and we can use several C# constructs such as Partial classes and Nested classes to achieve even better abstraction.

Points of Interest

In this article we get to learn some practical use of Nested and Partial classes in C#. These are two of the less known/used features in C# but if put to good use can be of great value as we did this in 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here