Factory design pattern and interfaces

Wednesday, 25 July 2007 23:22 GMT

A CLASS is often described as a blueprint for objects that are created from it. It specifies the behaviour of its instances and the data they contain (as methods and member variables, respectively).

In a similar way, an interface can be described as a set of requirements for classes. It can be regarded as a contract that specifies what methods should be present in the classes derived from it.

Taking manufacturing as an analogy, the interface represents the product specifications, and the class, the manufacturing specifications; the interface states what the product should look like, and the class describes what goes in the product.

Because the interface is such an abstract concept, many beginners in OOP fail to recognise how useful it can be for improving the design and robustness of their applications.

Here, I will try to demonstrate how the power of interfaces can be harnessed to add flexibility to an application.

Say, we are writing a module for storing user accounts to memory and an XML file interchangeably at runtime.

This requirement implies two different “storage” classes: one for memory storage and the other for XML file storage.


	public class BaseAccountStorage
	{
		public virtual void Save(Account account)
		{
			// Left blank intentionally		}
	}

	public class MemoryAccountStorage : BaseAccountStorage
	{
		public override void Save(Account account)
		{
			// Saves the account to memory
		}
	}

	public class XmlAccountStorage : BaseAccountStorage
	{
		public override void Save(Account account)
		{
			// Saves the account to an XML file
		}
	}

To save an account, the following code would be written.


	...
	public void SaveAccount(string destination, Account account)
	{
		BaseAccountStorage storage;

		if ("memory".Equals(destination))
		{
			storage = new MemoryAccountStorage();
		}
		else if ("xml".Equals(destination))
		{
			storage = new XmlAccountStorage();
		}

		storage.Save(account);
	}
	...

Introducing the Factory Design Pattern

Although this code works, it is not very flexible. For each new type of storage, we need to create an extra class and add a conditional statement to the SaveAccount method. This requires changes to both the storage library code and the client code using them.

To end this inconvenience, we create a class that is specialised inproducing storage objects of a specified type. Such a class is called a factory class and follows the Factory Design Pattern.

SIDENOTE: Factory Design Pattern

In real life, a factory is a highly specialised building fitted with machinery designed for the production of a unique product.

In object-oriented programming, the factory class is specialised in instantiating objects of a specific class.

Applying the Factory design pattern, we create the AccountStorageFactory class.


	public class AccountStorageFactory
	{
		string type;

		public AccountStorageFactory(string type)
		{
			this.type = type;
		}

		public BaseAccountStorage GetStorage()
		{
			BaseAccountStorage storage;

			if ("memory".Equals(type))
			{
				storage = new MemoryAccountStorage();
			}
			else if ("xml".Equals(type))
			{
				storage = new XmlAccountStorage();
			}

			return storage;
		}
	}

To use this class, we create an instance, passing the type of storage we want to the constructor. Then, we call the GetStorage method to obtain the storage object.

We change the client code accordingly.


	...
	public void SaveAccount(string type, Account account)
	{
		AccountStorageFactory f = new AccountStorageFactory(type);
		BaseAccountStorage storage = f.GetStorage();
		storage.Save(account);
	}
	...

We can already see the benefit of this approach. The client code does not have to concern itself with choosing which storage object to create; instead, it delegates this task to the AccountStorageFactory class.

If we need to have new storage types, we only have to create the appropriate sub-classes of BaseAccountStorage and modify the AccountStorageFactory.GetStorage class.

But, there is still one serious flaw in this design: we cannot be sure that a new storage class created by someone else will provide a Save method as expected by the client code. In other words, the extensibility of our solution is not assured.

Introducing the interface

Our basic definition of the interface at the beginning of this article states that it specifies what methods a class should expose. Therefore, we can use interfaces to address this issue.

SIDENOTE: Interface

If you recall from Computer 101, an interface is the means by which a user interacts with the computer. It can either be a physical device, for example, a keyboard, or it can be a software, for example, the command prompt. We also have programmatic interfaces, such as the .NET Framework.

In OOP, interface refers to the public methods of a class that can be called from client code.

We start by defining an IAccountStorage interface.


	public interface IAccountStorage
	{
		void Save(Account account);
	}

Notice the keyword interface.

Also notice that the Save method does not contain any code. This makes perfect sense, considering that an interface does nothing more than specifying what methods be present in sub-classes; it does not concern itself with how those methods are implemented. And, no accessibility modifier is specified for the Save method, as the methods defined in an interface are implicitly public.

SIDENOTE: Implementation

When a class inherits from an interface, we say that the class implements that interface. Sometimes, the class is said to be an implementation of the interface.

In Java, the keyword implements makes this clear. For example:


public class MemoryAccountStorage implements IAccountStorage {
...
}

Now that we have an interface, we modify our storage classes to inherit from it.


	public class MemoryAccountStorage : IAccountStorage
	{
		public void Save(Account account)
		{
			// Stores the account in memory
		}
	}

	public class XmlAccountStorage : IAccountStorage
	{
		public void Save(Account account)
		{
			// Stores the account to an XML file
		}
	}

Note that if these classes do not contain the Save methods as public, the code will not compile.

We need to modify the AccountStorageFactory class to return the new IAccountStorage mapping from the GetStorage method.


	public class AccountStorageFactory
	{
		string type;

		public AccountStorageFactory(string type)
		{
			this.type = type;
		}

		public IAccountStorage GetStorage()
		{
			IAccountStorage storage;

			if ("memory".Equals(type))
			{
				storage = new MemoryAccountStorage();
			}
			else if ("xml".Equals(type))
			{
				storage = new XmlAccountStorage();
			}

			return storage;
		}
	}

From now on, any class inheriting from IAccountStorage is assured to be a valid storage class for saving user accounts.

The client code also requires a slight change to accommodate the IAccountStorage interface.


	...
	public void SaveAccount(string type, Account account)
	{
		AccountStorageFactory f = new AccountStorageFactory(type);
		IAccountStorage storage = f.GetStorage();
		storage.Save(account);
	}
	...

At this point, our storage infrastructure for accounts is completed. But, we may want to make a more generic storage factory to produce storage objects for saving other types of objects, for example, contact details.

As you may have guessed, the use of interfaces is part of the solution once again. To be precise, we need a common ancestor from which all storage classes will be derived regardless of what objects they are designed to save.

This top-most interface is IStorage.


	public interface IStorage
	{
	}

We modify our IAccountStorage to inherit from IStorage.


	public interface IAccountStorage : IStorage
	{
		void Save(Account account);
	}

Let’s also add another hypothetical interface that will specify the requirement for storage classes responsible for saving contact details.


	public interface IContactStorage : IStorage
	{
		void Save(Contact contact);
	}

Then, the implementation.


	public class XmlContactStorage : IContactStorage
	{
		public void Save(Contact contact)
		{
			// Saves the contact to an XML file file
		}
	}

Perhaps the absence of methods in the IStorage interface puzzles you. This interface is what is known as a marker interface. It does nothing other than mark the type of interfaces and classes that are derived from it. It allows us to have a very generic factory class that creates objects from its sub-classes.


	public class StorageFactory
	{
		string type;

		public StorageFactory(string type)
		{
			this.type = type;
		}

		public IStorage GetStorage()
		{
			// Left blank intentionally
		}
	}

Our solution is not yet extensible enough if we still need conditional statements to determine what classes to instantiate. To fix this, we need a mapping of what “class” corresponds to what “type”.

So, we refine StorageFactory.


	public class StorageFactory
	{
		private Dictionary<string, Type> mapping;

		public StorageFactory(Dictionary<string, Type> mapping)
		{
			this.mapping = mapping;
		}

		public IStorage GetStorage(string name)
		{
			IStorage storage = null;

			if (mapping.ContainsKey(name))
			{
				Type type = mapping[name];
				storage = (IStorage) Activator.CreateInstance(type);
			}

			return storage;
		}
	}

There is quite a bit to digest here.

First, note that Type does not mean the same thing as the type variable in the AccountStorageFactory class. In this case, Type is a .NET Framework class that represents the type of an object.

The other thing to note is, we have made our factory more flexible. Instead of specialising in the production of only one type of storage classes, it can now produce different types (for account storage, for contact details storage, etc.) Actually, the StorageFactory can produce any storage class that implements the IStorage interface.

Then, there is a Dictionary object that holds the name-type mapping.

Finally, the GetStorage method itself has changed to instantiate objects on the fly by using the Activator.CreateInstance method. We will not go into the details of how that is done, but it suffices to know that the method allows us to create an instance of a given type. In this case, the Type that is instantiated is the one corresponding to name.

The StorageFactory class makes the AccountStorageFactory class obsolete since it can create different storage classes for different types of objects, including both Account and Contact objects.

Let’s rewrite our client code to take advantage of this new factory class.


	...
	StorageFactory factory;

	public void Initialise()
	{
		Dictionary<string, Type> mapping = new Dictionary<string, Type>();
		mapping.Add("account", typeof(MemoryAccountStorage));
		mapping.Add("contact", typeof(XmlContactStorage));

		factory = new StorageFactory(mapping);
	}

	public void SaveAccount(Account account)
	{
		IAccountStorage storage = (IAccountStorage) factory.GetStorage("account");
		storage.Save(account);
	}

	public void SaveContact(Contact contact)
	{
		IContactStorage storage = (IContactStorage) factory.GetStorage("contact");
		storage.Save(contact);
	}
	...

When the application is initialised, we define a mapping of storage name versus the implementation class. In this example, accounts are saved to memory storage, and contacts are saved to XML file storage, so we map “account” to MemoryAccountStorage, and “contact” to XmlContactStorage. We then create our factory, passing to it the mapping definitions.

Then, in the SaveAccount and SaveContact methods, we only have to pass the name of the storage we want to use to the GetStorage method, which returns the appropriate storage object.

All this just works thanks to the magic of interfaces. The StorageFactory.GetStorage method knows how to create IStorage implementations; therefore, any class that has IStorage up in its inheritance tree (as do MemoryAccountStorage and XmlContactStorage) can be instantiated from that method.

This concludes the tutorial on the factory design pattern and interfaces and how they can be harnessed to create extensible and robust application.

Eddy.

Popularity: 69% [?]

Possibly related:

2 Comments

RSS feed for comments on this post. TrackBack URI


  1. Very nice article :)

    Comment by Joel Wan — Tuesday, 31 July 2007 10:25 GMT #

  2. [...] In my previous post, I described how to use the Factory Design Pattern and interfaces to create a generic class that instantiate storage objects at run-time as specified in the configuration file of an application. [...]

    Pingback by Eddy Young » Abstract factory design pattern — Sunday, 5 August 2007 13:57 GMT #

Leave a comment



XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Powered by WordPress and Eddy Young.

DISCLAIMER: This site is supported by advertising. As a result, cookies may be installed by advertisers in order to track usage and trends. If you do not want this, please disable cookies for this site.