Jump to content

Factory (object-oriented programming)

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Ufo karadagli (talk | contribs) at 14:41, 15 June 2014 (PHP: Remove unnecessary semicolons in empty class declarations. In PHP you can add as many semicolons as you want at the end of the line.). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Factory Method in LePUS3

In object-oriented programming, a factory is an object for creating other objects – formally a factory is simply an object that returns an object from some method call, which is assumed to be "new".[a] More broadly, a subroutine that returns a "new" object may be referred to as a "factory", as in factory method or factory function. This is a basic concept in OOP, and forms the basis for a number of related software design patterns.

Motivation

In class-based programming, a factory is an abstraction of a constructor of a class, while in prototype-based programming a factory is an abstraction of a prototype object. A constructor is concrete in that it creates objects as instances of a single class, and by a specified process (class instantiation), while a factory can create objects by instantiating various classes, or by using other allocation schemes such as an object pool. A prototype object is concrete in that it is used to create objects by being cloned, while a factory can create objects by cloning various prototypes, or by other allocation schemes.

Factories may be invoked in various ways, most often a method call (a factory method), sometimes by being called as a function if the factory is a function object (a factory function). In some languages factories are generalizations of constructors, meaning constructors are themselves factories and these are invoked in the same way. In other languages factories and constructors are invoked differently, for example using the keyword new to invoke constructors but an ordinary method call to invoke factories; in these languages factories are an abstraction of constructors but not strictly a generalization, as constructors are not themselves factories.

Terminology

Terminology differs as to whether the concept of a factory is itself a design pattern – in the seminal book Design Patterns there is no "factory pattern", but instead two patterns (factory method pattern and abstract factory pattern) that use factories. Some sources refer to the concept as the factory pattern,[1][2] while others consider the concept itself a programming idiom,[3] reserving the term "factory pattern" or "factory patterns" to more complicated patterns that use factories, most often the factory method pattern; in this context, the concept of a factory itself may be referred to as a simple factory.[3] In other contexts, particularly the Python language, "factory" itself is used, as in this article.[4] More broadly, "factory" may be applied not just to an object that returns objects from some method call, but to a subroutine that returns objects, as in a factory function (even if functions are not objects) or factory method.[5] Because in many languages factories are invoked by calling a method, the general concept of a factory is often confused with the specific factory method pattern design pattern.

Use

Using factories instead of constructors or prototypes allows one to use polymorphism for object creation, not only object use. Specifically, using factories provides encapsulation, and means the code is not tied to specific classes or objects, and thus the class hierarchy or prototypes can be changed or refactored without needing to change code that uses them – they abstract from the class hierarchy or prototypes.

OOP provides polymorphism on object use by method dispatch, formally subtype polymorphism via single dispatch determined by the type of the object on which the method is called. However, this does not work for constructors, as constructors create an object of some type, rather than using an existing object. More concretely, when a constructor is called, there is no object yet on which to dispatch.[b]

More technically, in languages where factories generalize constructors, factories can usually be used anywhere constructors can be,[c] meaning that interfaces that accept a constructor can also in general accept a factory – usually one only need something that creates an object, rather than needing to specify a class and instantiation.

For example, in Python, the collections.defaultdict class[6] has a constructor which creates an object of type defaultdict[d] whose default values are produced by invoking a factory. The factory is passed as an argument to the constructor, and can itself be a constructor, or any thing that behaves like a constructor – a callable object that returns an object, i.e., a factory. For example, using the list constructor for lists:

# collections.defaultdict([default_factory[, ...]])
d = defaultdict(list)

Object creation

Factory objects are used in situations where getting hold of an object of a particular kind is a more complex process than simply creating a new object, notably if complex allocation or initialization is desired. Some of the processes required in the creation of an object include determining which object to create, managing the lifetime of the object, and managing specialized build-up and tear-down concerns of the object. 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. Similarly, using this definition, a singleton implemented by the singleton pattern is a formal factory – it returns an object, but does not create new objects beyond the single instance.

Examples

The simplest example of a factory is a simple factory function, which just invokes a constructor and returns the result. In Python, a factory function f that instantiates a class A can be implemented as:

def f():
  return A()

A simple factory function implementing the singleton pattern is:

def f():
  if not f.obj:
    f.obj = A()
  return f.obj

f.obj = None

This will create an object when first called, and always return the same object thereafter.

Syntax

Factories may be invoked in various ways, most often a method call (a factory method), sometimes by being called as a function if the factory is a callable object (a factory function). In some languages constructors and factories have identical syntax, while in others constructors have special syntax. In languages where constructors and factories have identical syntax, like Python, Perl, Ruby, Object Pascal, and F#[e], constructors can be transparently replaced by factories. In languages where they differ, one must distinguish them in interfaces, and switching between constructors and factories requires changing the calls.

Semantics

In languages where objects are dynamically allocated, as in Java or Python, factories are semantically equivalent to constructors. However, in languages such as C++ that allow some objects to be statically allocated, factories are different from constructors for statically allocated classes, as the latter can have memory allocation determined at compile time, while allocation of the return values of factories must be determined at run time. If a constructor can be passed as an argument to a function, then invocation of the constructor and allocation of the return value must be done dynamically at run time, and thus have similar or identical semantics to invoking a factory.

Design patterns

Factories are used in various design patterns, specifically in creational patterns. Specific recipes 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.

In some design patterns, a factory object 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.

Applications

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.[7]

Factories determine the actual concrete type of object to be created, and 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, not needing 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.

Applicability

Factories can be used when:

  1. The creation of an object makes reuse impossible without significant duplication of code.
  2. The creation of an object requires access to information or resources that should not be contained within the composing class.
  3. The lifetime management of the generated objects must be centralized to ensure a consistent behavior within the application.

Factories, specifically factory methods, are common in toolkits and frameworks, where library code needs to create objects of types that may be subclassed by applications using the framework.

Parallel class hierarchies often require objects from one hierarchy to be able to create appropriate objects from another.

Factory methods are used in test-driven development to allow classes to be put under test.[8] If such a class Foo creates another object Dangerous that can't be put under automated unit tests (perhaps it communicates with a production database that isn't always available), then the creation of Dangerous objects is placed in the virtual factory method createDangerous in class Foo. For testing, TestFoo (a subclass of Foo) is then created, with the virtual factory method createDangerous overridden to create and return FakeDangerous, a fake object. Unit tests then use TestFoo to test the functionality of Foo without incurring the side effect of using a real Dangerous object.

Benefits and variants

Besides use in design patterns, factories, especially factory methods, have various benefits and variations.

Descriptive names

A factory method has a distinct name. In many object-oriented languages, constructors must have the same name as the class they are in, which can lead to ambiguity if there is more than one way to create an object (see overloading). Factory methods have no such constraint and can have descriptive names; these are sometimes known as alternative constructors. As an example, when complex numbers are created from two real numbers the real numbers can be interpreted as Cartesian or polar coordinates, but using factory methods, the meaning is clear.

C#

    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, Math.PI);

When factory methods are used for disambiguation like this, the constructor is often made private to force clients to use the factory methods.

Java

The following example shows the implementation of complex numbers in Java:[9]

class Complex {
     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 * cos(angle), modulus * sin(angle));
     }
     private Complex(double a, double b) {
         //...
     }
}

Complex product = Complex.fromPolarFactory(1, pi);

VB.NET

The same example from above follows in VB.NET:

Public Class Complex
    Public Shared Function FromCartesianFactory(real As Double, imaginary As Double) As Complex
        Return New Complex(real, imaginary)
    End Function

    Public Shared Function FromPolarFactory(modulus As Double, angle As Double) As Complex
        Return New Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle))
    End Function

    Private Sub New(a As Double, b As Double)
        ' Private Constructor
    End Sub
End Class

Dim product As Complex = Complex.FromPolarFactory(1, Math.PI)

Encapsulation

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.

Consider as an example a program that reads image files. The program supports different image formats, represented by a reader class for each format.

Each time the program reads an image, it needs to create a reader of the appropriate type based on some information in the file. This logic can be encapsulated in a factory method. This approach has also been referred to as the Simple Factory

Java

public class ImageReaderFactory {
    public static ImageReader imageReaderFactoryMethod(ImageInputStreamProcessor iisp) {
        ImageReader product = null;

        if (iisp.isGIF()) {
          product = new GifReader(iisp.getInputStream());
        }
        else if (iisp.isJPEG()) {
          product = new JpegReader(iisp.getInputStream());
        }
        else {
          throw new IllegalArgumentException("Unknown image type.");
        }

        return product;
    }
}

PHP

class Factory
{
    public static function build($type)
    {
        $class = 'Format' . $type;
        if (!class_exists($class)) {
            throw new Exception('Missing format class.');
        }
        return new $class;
    }
}

class FormatString {}
class FormatNumber {}

try {
    $string = Factory::build('String');
} catch (Exception $e) {
    echo $e->getMessage();
}

try {
    $number = Factory::build('Number');
} catch (Exception $e) {
    echo $e->getMessage();
}

Notes

  1. ^ Interface-wise, any object that returns an object can be used as a factory, but semantically a factory returns either a newly created object, like a class instance or copy of a prototype, or an object that looks new, like a re-initialized object from an object pool.
  2. ^ In languages where constructors are themselves methods on a class object (class methods), there is an existing object, and constructors are special cases of factory methods, with polymorphic creation being a special case of polymorphic method dispatch. In other languages there is a sharp distinction between constructors and methods.
  3. ^ Constructors can be used anywhere factories can, since they are a special case.
  4. ^ This class is a subclass of dict, the built-in Python implementation of mappings or dictionaries.
  5. ^ If optional keyword new is omitted.

References

  1. ^ "Factory Pattern", OODesign.com
  2. ^ Factory Pattern, WikiWikiWeb
  3. ^ a b Chapter 4. The Factory Pattern: Baking with OO Goodness: The Simple Factory defined
  4. ^ "30.8 Classes Are Objects: Generic Object Factories", Learning Python, by Mark Lutz, 4th edition, O'Reilly Media, Inc., ISBN 978-0-596-15806-4
  5. ^ Factory Method, WikiWikiWeb
  6. ^ defaultdict objects
  7. ^ Feathers, Michael (October 2004). Working Effectively with Legacy Code. Upper Saddle River, NJ: Prentice Hall Professional Technical Reference. ISBN 978-0-13-117705-5.
  8. ^ Feathers, Michael (October 2004), Working Effectively with Legacy Code, Upper Saddle River, NJ: Prentice Hall Professional Technical Reference, ISBN 978-0-13-117705-5
  9. ^ Effective Java, Joshua Bloch, 2nd edition, page 5