Saturday, November 10, 2012

GOF : Creational 1. Factory Method Design pattern


What is a factory?

  • factory is an object for creating other objects. 
  • It is an abstraction of a constructor, and 
  • can be used to implement various allocation schemes. For example, using this definition, singletons implemented by the singleton pattern are formal factories.
  • A factory object typically has a method for every kind of object it is capable of creating. These methods optionally accept parameters defining how the object is created, and then return the created object.
  • Advance Use: The factory object might decide to create the object's class (if applicable) dynamically, return it from an object pool, do complex configuration on the object, or other things.
  • These kinds of objects have proven useful and several design patterns have been developed to implement them in many languages. For example, several "GoF patterns", like the "Factory method pattern", the "Builder" or even the "Singleton" are implementations of this concept. The "Abstract factory pattern" instead is a method to build collections of factories.
  • Factory objects are common in toolkits and frameworks where library code needs to create objects of types which may be subclassed by applications using the framework. They are also used in test-driven development to allow classes to be put under test.

Use of factory : Where and When

  • Factories determine the actual concrete type of object to be created, 
  • it is here that the object is actually created
  • As the factory only returns an abstract pointer, the client code does not know - and is not burdened by - the actual concrete type of the object which was just created. However, the type of a concrete object is known by the abstract factory. In particular, this means:

  • The client code has no knowledge whatsoever of the concrete type, so it does not need to include any header files or class declarations relating to the concrete type. 
  • The client code deals only with the abstract type. 
  • Objects of a concrete type are indeed created by the factory, but the client code accesses such objects only through their abstract interface.
  • Adding new concrete types is done by modifying the client code to use a different factory, a modification which is typically one line in one file. This is significantly easier than modifying the client code to instantiate a new type, which would require changing every location in the code where a new object is created.

Factory method Pattern 

Factory methods are static methods that return an instance of the native class. Examples in the JDK include :
Factory methods :
  • have names, unlike constructors, which can clarify code.
  • do not need to create a new object upon each invocation - objects can be cached and reused, if necessary.
  • can return a subtype of their return type - in particular, can return an object whose implementation class is unknown to the caller. This is a very valuable and widely used feature in many frameworks which use interfaces as the return type of static factory methods.
  • The creation of an object requires access to information or resources that should not be contained within the composing class
  • Common names for factory methods include getInstance and valueOf. These names are not mandatory - choose whatever makes sense for each case.
  • When factory methods are used for disambiguation like this, the constructor is often made private to force clients to use the factory methods.
  • Factory methods encapsulate the creation of objects. This can be useful, if the creation process is very complex; for example, if it depends on settings in configuration files or on user input.


public class Complex
    {
        public double real;
        public double imaginary;
 
        public static Complex FromCartesianFactory(double real, double imaginary ) 
        {
            return new Complex(real, imaginary);
        }
 
        public static Complex FromPolarFactory(double modulus , double angle ) 
        {
            return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle));
        }
 
 
        private Complex (double real, double imaginary)
        {
            this.real = real;
            this.imaginary = imaginary;
        }
    }
 
Complex product = Complex.FromPolarFactory(1,pi);


public class ComplexNumber {

  /**
  * Static factory method returns an object of this class.
  */
  public static ComplexNumber valueOf(float aReal, float aImaginary) {
    return new ComplexNumber(aReal, aImaginary);
  }

  /**
  * Caller cannot see this private constructor.
  *
  * The only way to build a ComplexNumber is by calling the static 
  * factory method.
  */
  private ComplexNumber (float aReal, float aImaginary) {
    fReal = aReal;
    fImaginary = aImaginary;
  }

  private float fReal;
  private float fImaginary;

  //..elided
} 

Limitations

There are three limitations associated with the use of the factory method. The first relates to refactoring existing code; the other two relate to extending a class.
  • The first limitation is that refactoring an existing class to use factories breaks existing clients. For example, if class Complex were a standard class, it might have numerous clients with code like:
Complex c = new Complex(-1, 0);
Once we realize that two different factories are needed, we change the class (to the code shown earlier). But since the constructor is now private, the existing client code no longer compiles.
  • The second limitation is that, since the pattern relies on using a private constructor, the class cannot be extended. Any subclass must invoke the inherited constructor, but this cannot be done if that constructor is private.
  • The third limitation is that, if we do extend the class (e.g., by making the constructor protected—this is risky but feasible), the subclass must provide its own re-implementation of all factory methods with exactly the same signatures. For example, if class StrangeComplex extends Complex, then unless StrangeComplex provides its own version of all factory methods, the call
    StrangeComplex.fromPolar(1, pi);
    
    will yield an instance of Complex (the superclass) rather than the expected instance of the subclass. The reflection features of some languages can obviate this issue.
All three problems could be alleviated by altering the underlying programming language to make factories first-class class members (see also Virtual class).[4]

      No comments:

      Post a Comment