Exemplifying the Factory Method Pattern inside the .NET Framework
page 2 of 6
by Xianzhong Zhu
Feedback
Average Rating: 
Views (Total / Last 10 Days): 34246/ 46

Using Factory Method Pattern to Better OOP

All OO languages have an idiom for object creation. However, the core of any OOP is the management of the objects. Of course, the first step of the object management is creating the object. In C#, this action is performed using the new operator. In essence, the true important part of managing an object is when to create the object.

As is well known, the types representing abstract definitions, such as interfaces and abstract classes, can not be used to create their respective instances. This means that the objects we want to create is relevant to concrete object types. i.e. the creation of the object is sure to involve the detail of implementation, which result in the close coupling between the creator and the concrete created object. Let us take an example, in the next section, to look more closely at this case.

Figure 1 - The initial idea in creating the objects required in the graphic project

At the first face, the structure in Figure 1 appropriately tallies with the OO idea. In terms of the polymorphism principle, we can substitute interface IShape for the two concrete classes (in this case Square and Circle) in practical programming, so that we defer the concrete object type binding to the running time. However, due to the face that we can not directly create the interface, once the IShape typed object requires to be created, we have to create the concrete class related object, as shown below.

Listing 1

IShape shape=new Square();

Suppose that you are developing a graphic tool, there will be lots of objects, such as Square and Circle, required to be created. Obviously, in each of the modules in this sample project, with so many of the above lines stuffed in it, it is very difficult for you to decouple the module from the Square object. When we require to change the object to create to Circle, all the modules that invoke the new Square() operation will have to be modified, which undoubtedly increases the quantity of modification, as well as results in the inextensibility of the project and the non-reusability of the modules. In this sense, the abstract interface IShape concerning the above graphic objects has now become an unnecessary and failed design.

So, what should we do with the above case? Ideally, we would kill this kind of diversification above in the cradle period. For this, we will have recourse to the principle of "Encapsulate Variety." With this idea, we can introduce the Factory Method pattern to encapsulate the creation of objects--the IShape typed objects are the products the factory needs to create. In the Factory Method pattern, the structure of the factory object should be in parallel with that of the products. Well, since there are two types of products (i.e. the Square and Circle), there also should be two corresponding concrete factory objects, SquareFactory and CircleFactory. And also, should abstract a related interface IShapeFactory for these two factories. Figure 2 indicates the relationships of these factory related objects.

Figure 2 - The factory class structure introduced by the Factory Method pattern

Below is the related code implementations.

Listing 2

public interface IShapeFactory
{
    IShape CreateShape();
}
public class SquareFactory : IShapeFactory
{
    public IShape CreateShape()
    {
        return new Square();
    }
}
public class SquareFactory : IShapeFactory
{
    public IShape CreateShape()
    {
        return new Square();
    }
}

As is indicated above, with the help of the Factory Method pattern, we have achieved the aim of encapsulating the creation of the objects, which shifts all the code creating concrete products to the respective factory objects, which is finally performed inside method CreateShape(). All these structures can be described using the diagram in Figure 3.

Figure 3 - The whole structure of the Factory Method pattern

Herein, the returned type of method CreateShape() is the type of interface IShape, which efficiently avoids the dependency between the factory objects and concrete product objects, decoupling the creator and the created object in the end.

Digging Further

Is that the final result? No! In essence, although we have introduced the Factory Method pattern in solving the above puzzles, we have not broken away from the heavy payload resulted from the creation of concrete objects. By digging further, it is not difficult to find out that although by introducing the Factory Method pattern the task of creating the IShape object is transferred to the factory object, the concrete factory object still exists inside the structure of the factory class. That is to say, we have cut off the dependency between the modules and the concrete graphic objects; however, this brings out the new dependency upon the concrete factory objects. What benefits does this bring to us?

Let us continue to do some research from the point of view of the creating frequency of the object. For a graphic tool, there is no doubt that the IShape object is frequently created, one of the possibilities is that the IShape object needs to be created in each module in the project. This, however, is not the case for the factory object; we can initialize the factory object in a central module and directly invoke the CreateShape method of the instance of the factory object when in need of the IShape object.

For example, suppose that in the graphic tool there are three modules, ModuleA, ModuleB, and ModuleC, all of which require creating the Square object. In the light of the original design solution, each module should contain the following:

Listing 3

IShape shape=new Square();

In this case, the above three modules all have dependency of the concrete Square object, as is shown in Figure 4 below. Well, suppose you want to change the shape object into the Circle type, this small alteration will surely influences upon every corner of the project.

Figure 4 - All the three modules rely heavily upon the graphic objects

Of course, we will have to continue to seek better solutions. Now, by introducing the Factory Method pattern, we can add a new module named ModuleFactory, inside which we create a factory object.

Listing 4

IShapeFactory shapeFactory=new SquareFactory();

With this new solution, ModuleA, ModuleB, and ModuleC should also be altered accordingly.

Listing 5

IShape shape=new shapeFactory.CreateShape();

By now, the three original modules have broken away from the dependency of concrete graphic objects; and also, this dependency has now been transferred to the ModuleFactory module. Figure 5 shows the new relationships after introducing the Factory Method pattern.

Figure 5

Well, when we are again in the face of the similar alteration requirement (requiring modifying the creation of the shape object), it becomes more feasible because the three modules (ModuleA, ModuleB, and ModuleC) are no longer dependent of the concrete graphic objects. What we need to modify is the parts (in this case the ModuleFactory module) that bear dependency of concrete graphic objects. Please check out the following:

Listing 6

IShapeFactory sf=new CircleFactory();

By distinguishing Figure 4 from Figure 5, you can easily find out that with the introduction of the Factory Method pattern the whole design has been drastically improved. Despite that we have introduced three new factory objects and the new ModuleFactory module; they together have decoupled the three modules with concrete graphic objects, so that this dependency is shifted into only one module -- ModuleFactory.

Altogether, introducing the factory object does not only mean to build up the corresponding factory for each product, but to care more about the compartmentalization of the responsibilities of different modules so as to put the creation of the factory at the most proper site. Numerous design facts prove that the best solution is to centralize the responsibility of creating the factory object in a module, but not to create the factory objects just when in need of create concrete products.


View Entire Article

User Comments

Title: Images missing   
Name: James
Date: 2013-01-21 4:01:32 PM
Comment:
Hey all figure images are missing. Can you fix this??
Title: Amazing   
Name: Nimesh
Date: 2010-08-04 9:11:39 PM
Comment:
Hi Xianzhong Zhu,
I can stop praising you for this article. It has answered so many of my questions along the way of learning new things. You should never stop writing such interesting articles man.

Carry on mate,

Nimesh






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 12:53:49 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search