Powered by Blogger.

Wednesday, July 21, 2010

The Factory Method (Creational) Design Pattern

The Problem One of the goals of object-oriented design is to delegate responsibility among different objects. This kind of partitioning is good since it encourages Encapsulation and Delegation.
  • Sometimes, an Application (or framework) at runtime, cannot anticipate the class of object that it must create. The Application (or framework) may know that it has to instantiate classes, but it may only know about abstract classes (or interfaces), which it cannot instantiate. Thus the Application class may only know when it has to instantiate a new Object of a class, not what kind of subclass to create.
  • a class may want it's subclasses to specify the objects to be created.
  • a class may delegate responsibility to one of several helper subclasses so that knowledge can be localized to specific helper subclasses.
The Solution Factory Method is a creational pattern. This pattern helps to model an interface for creating an object which at creation time can let its subclasses decide which class to instantiate. We call this a Factory Pattern since it is responsible for "Manufacturing" an Object. It helps instantiate the appropriate Subclass by creating the right Object from a group of related classes. The Factory Pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code. Factories have a simple function: Churn out objects. Obviously, a factory is not needed to make an object. A simple call to new will do it for you. However, the use of factories gives the programmer the opportunity to abstract the specific attributes of an Object into specific subclasses which create them. The Factory Pattern is all about "Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses" Thus, as defined by Gamma et al, "The Factory Method lets a class defer instantiation to subclasses". Figure 1 below illustrates the roles of the Factory Pattern.
Figure 1: The roles of the Factory Pattern
As shown in the figure, the Factory Pattern has a couple of roles - a Creator and a Concrete Creator. This pattern is used when a class (the Creator) does not know beforehand all the subclasses that it will create. Instead, each subclass (the Concrete Creator) is left with the responsibility of creating the actual object instances. Explanation Example Scenario 1 - One typical use of the Factory Pattern in a Component Object Model (COM) application: In this scenario, the Creator is played by a COM interface called the IClassFactory and the Concrete Creator is played by the class which implements that interface. COM alleviates the need for the COM runtime to know about all the possible object types that it needs to create ahead of time. Typically, Object creation may require acquisition of system resources, coordination between several Objects, etc. With the introduction of the IClassFactory interface, all the details of object creation can be hidden in a Concrete derivation, manifested as a Class Factory. This way, it is only the class factory that has to be explicitly created by the COM support system. Figure 2 below, shows the control flow details of component creation from the client using the Factory Pattern in a typical COM application.
Figure 2: Control Flow Details of Component Creation from the client using a Factory Pattern approach in COM
As shown in figure 2, the client first calls CoCreateInstance, which is implemented in the COM library. CoCreateInstance is implemented using CoGetClassObject. CoGetClassObject looks for the component in the Windows Registry. If it finds the component in the registry, it loads the associated DLL that serves the component. After the DLL is loaded, CoGetClassObject calls the DllGetClassObject. DllGetClassObject is implemented in the DLL Server. It's job is to create the Class Factory which it does using the new operator. DllGetClassObject then queries the Class Factory for the IClassFactory interface, which is returned to CoCreateInstance. CoCreateInstance then uses the IClassFactory interface to call it's CreateInstance function. Here, IClassFactory::CreateInstance calls the new operator to create the component. In addition, it queries for the IAccount interface. After getting the interface, CoCreateInstance releases the Class Factory and returns the IAccount interface pointer to the client. The client can now use the interface pointer to call methods on the component.
Example Scenario 2- One typical use of the Factory Pattern in the Standard Template Library (STL): In the STL, an iterator is a sort of smart pointer for which the operator*() function is overloaded in order to provide not the iterator object itself but the individual data object in the container, such as a table row. Because the iterator must have knowledge of the container internals in order to traverse the data structure, the definition of the iterator class is included with each container in the STL; Gamma et al would probably include this as an example of a Factory design pattern, in that the container, in a way, creates the iterator. In other words, the list makes its iterator. "Iterator'' itself is also a design pattern described by Gamma et al (which we will discuss in a future article).
Example Scenario 3- One typical use of the Factory Pattern in an Enterprise JavaBean (EJB) Application: An entity bean is an object representation of persistent data that are maintained in a permanent data store, such as a database. A primary key identifies each instance of an entity bean. Entity beans can be created by creating an object using an object factory Create method. Similarly, Session beans can be created by creating an object using an object factory Create method.
Figure 3 below, shows the control flow details of component creation from the client using the Factory Pattern in a typical EJB application.
Figure 3: Control Flow Details of Component Creation from the client using a Factory Pattern approach in EJB
Starting at the top left of the image, the client first creates a new context to look up the EJBObject with the help of a JNDI server. Given this context, the client then creates an EJB using the home interface. The client can then call the available methods of the EJBObject. When all the activities are complete, the client calls the remove() method, also through the home interface, to terminate the session. The equivalent code for the same looks like Listing 1:
import javax.naming.*;
public class EJBClient {
 
 public static void main (String[] argv) {
  
  // get the JNDI naming context  Context initialCtx = new InitialContext ();
  // use the context to lookup the EJB Home interface  AccountHome home=(AccountHome)initialCtx.lookup("Account");
  // use the Home Interface to create a Session bean object  Account account = home.create (10001, "Athul", 100000000.25d);
  // invoke business methods  account.credit (200000000.25d);
  // remove the object  account.remove ();
 }
}
Listing 1: The EJB Client code to talk to an EJB
Example Scenario 4- One typical use of the Factory Pattern in the Common Object Request Broker Architecture (CORBA): The CORBA Object Services - Naming Service Specification (COSNaming), describes the entire namespace in terms of NamingContext Objects. These contexts can be connected to each other and can contain references to actual object instances for which clients will ask. The contexts are all contained within the CosNaming.Factory and CosNaming.ExtFactory servers. When the factory server is executed, it always creates a singleton persistent object implementing the CosNaming::NamingContextFactory interface. All NamingContext objects created within a particular factory server are associated with that server's single NamingContextFactory. The factories support the following interfaces as shown in Listing 2:
// CORBA Interface Definition Languagemodule CosNaming {
 interface NamingContextFactory {
 NamingContext create_context ();
 oneway void shutdown ();
 };
 interface ExtendedNamingContextFactory : NamingContextFactory {
  NamingContext root_context ();
 };
};
Listing 2: The COSNaming interface in CORBA is modelled using the Factory Pattern
Implementation
Our Example: To restrict access to authorized personnel and to prevent information glut by loading users with information that would be useless to them, lots of ecommerce applications, provide profile management by storing static and dynamic information about users. Providing individual or multiple users access to resources such as individual files, directory structures, user-defined entities (such as catalogs, purchase orders etc.) etc., can be controlled based on the individual/group's organization/role with and within an organization. Our example here, ensures information control, by providing Employees with access to Confidential Resources, while restricting the generic public to only Public Resources.
We will use this example to illustrate the different implementation options available to us.
The Classes and Interfaces used:
Figure 4: The Creator as an Abstract Class (*)
1. Resource - An abstract base class that defines a common interface to different types of Resources in an Organization. These resources may represent individual files, directory structures, user-defined entities (such as catalogs, purchase orders etc.) etc. The listings below, illustrate how the Resource class is implemented in Java and C++.
In Java,
public abstract class Resource {
  public abstract void printMessage ();
}
Listing 3: Resource.java
In C++,
#include <stdio.h>
class CResource {
public:
  CResource() {}
  virtual ~CResource() {}
  virtual void printMessage () = 0;
};
Listing 4: Resource.h
2. ConfidentialResource - A specialization of the Resource interface which represents resources which are Company Confidential resources which may not be accessed by anyone except the Company Employees.The listings below, illustrate how the ConfidentialResource class is implemented in Java and C++.
In Java,
public class ConfidentialResource extends Resource {
  public void printMessage ()
  { System.out.println ("This is a Company Confidential Resource..."); }
}
Listing 5: ConfidentialResource.java
In C++,
#include "Resource.h"
class CConfidentialResource : public CResource {
public:
  CConfidentialResource() {}
  virtual ~CConfidentialResource() {}
  virtual void printMessage (void) {
    printf ("This is a Company Confidential Resource...\n");
  }
};
Listing 6: ConfidentialResource.h
3. PublicResource - A specialization of the Resource interface which represents resources which are available to anyone.The listings below, illustrate how the PublicResource class is implemented in Java and C++.
In Java,
public class PublicResource extends Resource {
  public void printMessage ()
  { System.out.println ("This is a Public Resource..."); }
}
Listing 7: PublicResource.java
In C++,
#include "Resource.h"
class CPublicResource : public CResource {
public:
  CPublicResource() {}
  virtual ~CPublicResource() {}
  virtual void printMessage (void) {
    printf ("This is a Public Resource...\n");
  }
};
Listing 8: PublicResource.h
4. Profile - An abstract base class that defines a common interface to hold information about users like their Name, EMail Address, etc. A getResource() method is used to retrieve a reference to Resources. Employees have access to ConfidentialResources whereas, Non-Employees have access to PublicResources. The listings below, illustrate how the Profile class is implemented in Java and C++.
In Java,
public abstract class Profile {
  public Profile (String sName, String sEmail) {
    m_sName = sName;
    m_sEmail = sEmail;
  }
  
  public String getName ()     { return m_sName; }
  public String getEmail ()    { return m_sEmail; }
  public boolean IsEmployee () { return m_bIsEmployee; }

  public abstract Resource getResource ();
  
  protected String  m_sName, 
                    m_sEmail;
  protected boolean m_bIsEmployee;
}
Listing 9: Profile.java
In C++,
#include <string.h>
#include "Resource.h"
#include "ResourceCreator.h"
class CProfile {
public:
  CProfile(char* psName, char* psEmail) {
    if (psName) {
      m_psName = new char [strlen(psName)+1];
      strcpy (m_psName, psName);
    }
    if (psEmail) {
      m_psEmail = new char [strlen(psEmail)+1];
      strcpy (m_psEmail, psEmail);
    }
  }
  virtual ~CProfile() {
    delete [] m_psName;
    delete [] m_psEmail;
  }
  virtual char* getName (void) { return m_psName; }
  virtual char* getEmail (void) { return m_psEmail; }
  virtual bool  IsEmployee (void) { return m_bIsEmployee; }
  virtual CResource* getResource (void) = 0;
  protected:
  char *m_psName;
  char *m_psEmail;
  bool m_bIsEmployee;
};
Listing 10: Profile.h
5. Employee - A specialization of the Profile interface represents an Object associated with an Employee of the Company. The IsEmployee() method returning a boolean value is used to test to see if the Object represents an employee of the Company.
6. NonEmployee - A specialization of the Profile interface represents an Object associated with users who are Non-Employee of the Company. The IsEmployee() method returning a boolean value is used to test to see if the Object represents an employee of the Company.
Implementation 1 - When the Creator class is an Abstract class: This requires subclasses to define an implementation, because there is no reasonable default. It gets around the dialemma of having to instantiate unforeseeable classes.
public class Employee extends Profile {
  public Employee (String sName, String sEmail) {
    super (sName, sEmail);
    m_bIsEmployee = true;
  }
  public Resource getResource () { return new ConfidentialResource (); }
  }
Listing 11: Employee.java
public class NonEmployee extends Profile {
  public NonEmployee (String sName, String sEmail) {
    super (sName, sEmail);
    m_bIsEmployee = false;
  }
  public Resource getResource () { return new PublicResource (); }
}
Listing 12: NonEmployee.java
public class FactoryPattern {
  public static void main (String[] args) {
    Employee employee = new Employee ("Athul", "athul@eCommWare.com");
    NonEmployee nonEmployee = new NonEmployee ("Aditya", "aditya@inventor.com");

    employee.getResource ().printMessage ();
    nonEmployee.getResource ().printMessage ();
  }
}
Listing 13: FactoryPattern.java
Implementation 2 - When the Creator class is a Concreate class: In this type of implementation, the concrete Creator uses the factory method primarily for flexibility. It says "Create objects in a separate operation so that subclasses can change the way they are created". This ensures that, if necessary, designers of subclasses can change the class of objects their parent class instantiates.
Implementation 3 - Parameterized Factory Methods: This type of implementation lets the factory method create multiple kinds of Objects. The factory method takes a parameter that identifies the kind of object to create. All Objects that the factory method creates, share the same interface. Once the identifier is read, the framework calls createResource () with the identifier passed in. The createResource () method instantiates and returns the appropriate Resource reference.
public class ResourceCreator {
  public static final int CONFIDENTIAL = 0;
  public static final int PUBLIC = 1;
  public Resource createResource (int nID) {
    switch (nID) {
      case CONFIDENTIAL:
        return new ConfidentialResource ();
      case PUBLIC:
        return new PublicResource ();
    }
    return null;
  }
}
Listing 14: ResourceCreator.java
public class Employee extends Profile {
  public Employee (String sName, String sEmail) {
    super (sName, sEmail);
    m_bIsEmployee = true;
  }
  public Resource getResource () {
    ResourceCreator creator = new ResourceCreator ();
    return creator.createResource (ResourceCreator.CONFIDENTIAL);
  }
}
Listing 15: Employee.java
public class NonEmployee extends Profile {
  public NonEmployee (String sName, String sEmail) {
    super (sName, sEmail);
    m_bIsEmployee = false;
  }
  public Resource getResource () {
    ResourceCreator creator = new ResourceCreator ();
    return creator.createResource (ResourceCreator.PUBLIC);
  }
}
Listing 16: NonEmployee.java
Implementation 4 - Using Templates to avoid subclassing: A potential problem with factory methods is that they might force you to subclass just to create the appropriate Objects. One way to get around this in C++ is to provide a template subclass of the Creator class that's parameterized by the appropriate object class.
template <class aResource>
class CResourceCreator {
public:
  virtual CResource* createResource ();
};
template <class aResource>
CResource* CResourceCreator<aResource>::createResource () {
  return new aResource;
}
Listing 17: ResourceCreator.h
#include "Profile.h"
#include "ConfidentialResource.h"
class CEmployee : public CProfile {
public:
  CEmployee (char* psName, char* psEmail)
    : CProfile (psName, psEmail) {
    m_bIsEmployee = true;
  }
  virtual ~CEmployee() {}
  virtual CResource* getResource (void) {
    CResourceCreator<CConfidentialResource> creator;
    return creator.createResource ();
  }
};
Listing 18: Employee.h
#include "Profile.h"
#include "PublicResource.h"
class CNonEmployee : public CProfile {
public:
  CNonEmployee (char* psName, char* psEmail) 
    :CProfile  (psName, psEmail) {
    m_bIsEmployee = false;
  }
  virtual ~CNonEmployee() {}
  virtual CResource* getResource (void) {
    CResourceCreator<CPublicResource> creator;
    return creator.createResource ();
  }
};
Listing 19: NonEmployee.h
#include "Resource.h"
#include "Employee.h"
#include "NonEmployee.h"
int main(int argc, char* argv[]) {
  CEmployee employee ("Athul", "athul@eCommWare.com");
  CNonEmployee nonEmployee ("Aditya", "aditya@inventor.com");
  
  employee.getResource ()->printMessage ();
  nonEmployee.getResource ()->printMessage ();

  return 0;
}
Listing 20: FactoryPattern.cpp
Checks and Balances of using this pattern
Plusses Minus
  • Eliminates the need to bind application-specific classes into your code
  • Provides hooks for subclassing. Creating objects inside a class with a factory method is always more flexible than creating an object directly. This method gives subclasses a hook for providing an extended version of an object
  • Connects parallel heirarchies. Factory method localises knowledge of which classes belong together. Parallel class heirarchies result when a class delegates some of its responsibilities to a separate class.
  • Clients might have to subclass the Creator class just to create a particular Concreate object.

No comments:

Post a Comment

  ©Template by Dicas Blogger.

TOPO