Factory (object-oriented programming): Difference between revisions
Jerryobject (talk | contribs) 'Image:' > 'File:' update-standardize. WP:REFerence WP:CITation parameters: reorders, respaces, cut whitespace characters to standardize, aid work via small screens, update-standardize-conform. WP:BADEMPHASIS MOS:QUOTEMARKS > WP:ITALICs or cut. Small WP:COPYEDITs WP:EoS: WP:TERSE, clarify. WP:LINKs: adds, update-standardizes, needless WP:PIPEs > WP:NOPIPEs. 1st MOS:PERSONs we cut+fix. Adds: WP:CATEGORY, MOS:COMMENT. |
|||
(32 intermediate revisions by 24 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Object that creates other objects}} |
|||
{{ |
{{Redirect|Factory pattern|the GoF design patterns using factories|factory method pattern|and|abstract factory pattern}} |
||
[[ |
[[File:Factory Method pattern in LePUS3.png|thumb|right|300px|Factory Method in LePUS3]] |
||
⚫ | In [[object-oriented programming |
||
⚫ | In [[object-oriented programming]], a '''factory''' is an [[Object (computer science)|object]] for [[object creation|creating other objects]]; formally, it is a [[Subroutine|function]] or [[Method (computer programming)|method]] that returns objects of a varying prototype or [[Class (computer programming)|class]]<ref>{{Cite book|last1=Gamma|first1=Erich|year=1994|title=Design Patterns|publisher=Addison-Wesley|isbn=9780321700698|pages=18–19}}</ref> from some method call, which is assumed to be ''new''.{{efn|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 (computer science)|instance]] or copy of a prototype, or an object that looks new, like a re-initialized object from an object pool.}} More broadly, a subroutine that returns a ''new'' object may be referred to as a ''factory'', as in ''factory method'' or ''factory function''. The factory pattern is the basis for a number of related [[software design pattern]]s. |
||
==Motivation== |
|||
⚫ | In [[class-based programming]], a factory is an [[abstraction (computer science)|abstraction]] of a [[Constructor (object-oriented programming)|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 |
||
==Motive== |
|||
⚫ | |||
⚫ | In [[class-based programming]], a factory is an [[abstraction (computer science)|abstraction]] of a [[Constructor (object-oriented programming)|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 [[Instance (computer science)|instances]] of one class, and by a specified process (class instantiation), while a factory can create objects by instantiating various classes, or by using other allocation means, such as an [[object pool]]. A prototype object is concrete in that it is used to create objects by being [[Cloning (programming)|cloned]], while a factory can create objects by cloning various prototypes, or by other allocation means. |
||
⚫ | A factory may be implemented in various ways. Most often it is implemented as a method, in which case it is called a ''[[factory method]]''. Sometimes it is implemented as a function, in which case it is called a ''factory function''. In some languages, constructors are factories. However, in most languages they are not, and constructors are invoked in a way that is idiomatic to the language, such as by using the keyword <code>new</code>, while a factory has no special status and is invoked via an ordinary method call or function call. In these languages, a factory is an abstraction of a constructor, but not strictly a generalization, as constructors are not factories. |
||
==Terminology== |
==Terminology== |
||
Terminology differs as to whether the concept of a factory is |
Terminology differs as to whether the concept of a factory is a design pattern – in ''[[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'',<ref name=oodesign>''[http://www.oodesign.com/factory-pattern.html Factory Pattern]'', [http://www.oodesign.com/ OODesign.com]</ref><ref>[http://c2.com/cgi/wiki?FactoryPattern Factory Pattern], [[WikiWikiWeb]]</ref> while others consider the concept a [[programming idiom]],<ref name=headfirst>[http://my.safaribooksonline.com/0596007124/ch04_html Chapter 4. The Factory Pattern: Baking with OO Goodness] {{Webarchive|url=https://web.archive.org/web/20170311165428/http://my.safaribooksonline.com/0596007124/ch04_html |date=2017-03-11}}: [http://my.safaribooksonline.com/book/software-engineering-and-development/patterns/0596007124/4dot-the-factory-pattern-baking-with-oo-goodness/simple_factory_defined_html The Simple Factory defined] {{Webarchive|url=https://web.archive.org/web/20140219063540/http://my.safaribooksonline.com/book/software-engineering-and-development/patterns/0596007124/4dot-the-factory-pattern-baking-with-oo-goodness/simple_factory_defined_html |date=2014-02-19}}</ref> 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 may be referred to as a ''simple factory''.<ref name=headfirst/> In other contexts, particularly the [[Python (programming language)|Python]] language, the term ''factory'' is used, as in this article.<ref>''[https://www.inkling.com/read/learning-python-mark-lutz-4th/chapter-30/classes-are-objects-generic 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}}</ref> 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''.<ref>[http://c2.com/cgi/wiki?FactoryMethod Factory Method], [[WikiWikiWeb]]</ref> 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== |
==Use== |
||
OOP provides [[Polymorphism (computer science)|polymorphism]] on object ''use'' by [[method dispatch]], formally [[subtype |
OOP provides [[Polymorphism (computer science)|polymorphism]] on object ''use'' by [[method dispatch]], formally [[Subtyping|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 ''use'' an existing object. More concretely, when a constructor is called, there is no object yet on which to dispatch.{{efn|In languages where constructors are methods on a class object ([[class method]]s), 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.}} |
||
Using factories instead of constructors or prototypes allows one to use polymorphism for object creation, not only object use. Specifically, using factories provides [[Encapsulation (object-oriented programming)|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. |
Using factories instead of constructors or prototypes allows one to use polymorphism for object creation, not only object use. Specifically, using factories provides [[Encapsulation (object-oriented programming)|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. |
||
Line 18: | Line 20: | ||
More technically, in languages where factories generalize constructors, factories can usually be used anywhere constructors can be,{{efn|Constructors can be used anywhere factories can, since they are a special case.}} 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. |
More technically, in languages where factories generalize constructors, factories can usually be used anywhere constructors can be,{{efn|Constructors can be used anywhere factories can, since they are a special case.}} 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 <code>collections.defaultdict</code> class<ref>[https://docs.python.org/3/library/collections.html#defaultdict-objects defaultdict objects]</ref> has a constructor which creates an object of type <code>defaultdict</code>{{efn|This class is a subclass of <code>dict</code>, the built-in Python implementation of mappings or dictionaries.}} whose default values are produced by invoking a factory. The factory is passed as an argument to the constructor, and can |
For example, in Python, the <code>collections.defaultdict</code> class<ref>[https://docs.python.org/3/library/collections.html#defaultdict-objects defaultdict objects]</ref> has a constructor which creates an object of type <code>defaultdict</code>{{efn|This class is a subclass of <code>dict</code>, the built-in Python implementation of mappings or dictionaries.}} whose default values are produced by invoking a factory. The factory is passed as an argument to the constructor, and can 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 <code>list</code> constructor for lists: |
||
< |
<syntaxhighlight lang="python"> |
||
# collections.defaultdict([default_factory[, ...]]) |
# collections.defaultdict([default_factory[, ...]]) |
||
d = defaultdict(list) |
d = defaultdict(list) |
||
</syntaxhighlight> |
|||
</source> |
|||
===Object creation=== |
===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 [[ |
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 (computer programming)|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 (mathematics)|singleton]] implemented by the [[singleton pattern]] is a formal factory – it returns an object, but does not create new objects beyond the one instance. |
||
==Examples== |
==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 <code>f</code> that instantiates a class <code>A</code> can be implemented as: |
The simplest example of a factory is a simple factory function, which just invokes a constructor and returns the result. In [[Python (programming language)|Python]], a factory function <code>f</code> that instantiates a class <code>A</code> can be implemented as: |
||
< |
<syntaxhighlight lang="python"> |
||
def f(): |
def f(): |
||
return A() |
return A() |
||
</syntaxhighlight> |
|||
</source> |
|||
A simple factory function implementing the singleton pattern is: |
A simple factory function implementing the singleton pattern is: |
||
< |
<syntaxhighlight lang="python"> |
||
def f(): |
def f(): |
||
if f.obj is None: |
if f.obj is None: |
||
Line 42: | Line 44: | ||
f.obj = None |
f.obj = None |
||
</syntaxhighlight> |
|||
</source> |
|||
This will create an object when first called, and always return the same object thereafter. |
This will create an object when first called, and always return the same object thereafter. |
||
==Syntax== |
==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#,{{efn|If optional keyword <code>new</code> is omitted.}} 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. |
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 (programming language)|Ruby]], [[Object Pascal]], and [[F Sharp (programming language)|F#]],{{efn|If optional keyword <code>new</code> is omitted.}} 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== |
==Semantics== |
||
In languages where objects are [[Dynamic memory allocation|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. |
In languages where objects are [[Dynamic memory allocation|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== |
==Design patterns== |
||
{{ |
{{Further|Creational pattern}} |
||
Factories are used in various [[Design pattern (computer science)|design patterns]], specifically in [[creational pattern]]s such as the [[Design pattern object library]]. Specific recipes have been developed to implement them in many languages. For example, several |
Factories are used in various [[Design pattern (computer science)|design patterns]], specifically in [[creational pattern]]s such as the [[Design pattern object library]]. Specific recipes have been developed to implement them in many languages. For example, several ''[[Design Patterns (book)|GoF patterns]]'', like the ''[[Factory method pattern]]'', the ''[[Builder pattern|Builder]]'' or even the ''[[Singleton pattern|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 [[ |
In some design patterns, a factory object has a [[Method (computer programming)|method]] for every kind of object it can create. These methods optionally accept [[parameter]]s defining how the object is created, and then return the created object. |
||
==Applications== |
==Applications== |
||
Factory objects are common in [[toolkit]]s and [[ |
Factory objects are common in [[widget toolkit]]s and [[software framework]]s where [[Library (computing)|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.<ref>{{cite book |
||
| |
|last1=Feathers |
||
| |
|first1=Michael |
||
⚫ | |||
|isbn=978-0-13-117705-5 |
|isbn=978-0-13-117705-5 |
||
|title=Working Effectively with Legacy Code |
|title=Working Effectively with Legacy Code |
||
⚫ | |||
|publisher=Prentice Hall Professional Technical Reference |
|publisher=Prentice Hall Professional Technical Reference |
||
|location=Upper Saddle River, |
|location=Upper Saddle River, New Jersey |
||
}}</ref> |
}}</ref> |
||
Factories determine the ''concrete'' type of [[Object (computer science)|object]] to be created, and it is here that the object is created. As the factory only returns an abstract interface to the object, the client code does not know, and is unburdened by, the 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 [[data type]], not needing to include any [[header file]]s or [[Class (computer programming)|class]] [[Declaration (computer programming)|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 == |
== Applicability == |
||
Factories can be used when: |
Factories can be used when: |
||
# |
# Creating an object makes reuse impossible without significant duplication of code. |
||
# |
# Creating an object requires access to information or resources that should not be contained within the composing class. |
||
# |
# Managing the lifetime of generated objects must be centralized to ensure consistent behavior within an application. |
||
Factories, specifically factory methods, are common in [[toolkit]]s and [[ |
Factories, specifically factory methods, are common in [[widget toolkit]]s and [[software framework]]s, 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. |
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.<ref>{{ |
Factory methods are used in [[test-driven development]] to allow classes to be put under test.<ref>{{cite book |
||
| |
|last1=Feathers |
||
|first1=Michael |
|||
⚫ | |||
⚫ | |||
| |
|title=Working Effectively with Legacy Code |
||
⚫ | |||
| |
|publisher=Prentice Hall Professional Technical Reference |
||
| |
|location=Upper Saddle River, NJ |
||
⚫ | |||
}}</ref> If such a class <code>Foo</code> creates another object <code>Dangerous</code> that can't be put under automated [[unit test]]s (perhaps it communicates with a production database that isn't always available), then the creation of <code>Dangerous</code> objects is placed in the [[virtual function|virtual]] factory method <code>createDangerous</code> in class <code>Foo</code>. For testing, <code>TestFoo</code> (a subclass of <code>Foo</code>) is then created, with the virtual factory method <code>createDangerous</code> overridden to create and return <code>FakeDangerous</code>, a [[fake object]]. Unit tests then use <code>TestFoo</code> to test the functionality of <code>Foo</code> without incurring the side effect of using a real <code>Dangerous</code> object. |
}}</ref> If such a class <code>Foo</code> creates another object <code>Dangerous</code> that can't be put under automated [[unit test]]s (perhaps it communicates with a production database that isn't always available), then the creation of <code>Dangerous</code> objects is placed in the [[virtual function|virtual]] factory method <code>createDangerous</code> in class <code>Foo</code>. For testing, <code>TestFoo</code> (a subclass of <code>Foo</code>) is then created, with the virtual factory method <code>createDangerous</code> overridden to create and return <code>FakeDangerous</code>, a [[fake object]]. Unit tests then use <code>TestFoo</code> to test the functionality of <code>Foo</code> without incurring the side effect of using a real <code>Dangerous</code> object. |
||
Line 92: | Line 100: | ||
===Descriptive names=== |
===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 [[ |
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 [[Polymorphism (computer science)#Overloading|overloading]]). Factory methods have no such constraint and can have descriptive names; these are sometimes known as ''alternative constructors''. As an example, when [[complex number]]s 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, as illustrated by the following example in [[C Sharp (programming language)|C#]]. |
||
< |
<syntaxhighlight lang="csharp"> |
||
public class Complex |
|||
{ |
|||
⚫ | |||
public double _imaginary; |
|||
⚫ | |||
{ |
{ |
||
return new Complex(real, imaginary); |
|||
⚫ | |||
⚫ | |||
public static Complex FromPolar(double modulus, double angle) |
|||
{ |
|||
return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle)); |
|||
} |
|||
private Complex(double real, double imaginary) |
|||
{ |
|||
⚫ | |||
return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle)); |
|||
this._imaginary = imaginary; |
|||
⚫ | |||
{ |
|||
⚫ | |||
this.imaginary = imaginary; |
|||
⚫ | |||
} |
} |
||
} |
|||
Complex product = Complex.FromPolar(1, Math.PI); |
Complex product = Complex.FromPolar(1, Math.PI); |
||
</syntaxhighlight> |
|||
</source> |
|||
When factory methods are used for disambiguation like this, the raw constructors are often made private to force clients to use the factory methods. |
When factory methods are used for disambiguation like this, the raw constructors are often made private to force clients to use the factory methods. |
||
Line 128: | Line 136: | ||
Consider as an example a program that reads [[image file]]s. The program supports different image formats, represented by a reader class for each format. |
Consider as an example a program that reads [[image file]]s. 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 |
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==== |
====Java==== |
||
{{Further|Java (programming language)}} |
|||
<source lang=Java> |
|||
<syntaxhighlight lang="java"> |
|||
public class ImageReaderFactory { |
public class ImageReaderFactory { |
||
public static ImageReader createImageReader(ImageInputStreamProcessor iisp) { |
public static ImageReader createImageReader(ImageInputStreamProcessor iisp) { |
||
Line 145: | Line 154: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
====PHP==== |
====PHP==== |
||
{{Further|PHP}} |
|||
<source lang=PHP> |
|||
<syntaxhighlight lang="php"> |
|||
class Factory |
class Factory |
||
{ |
{ |
||
public static function build($type) |
public static function build(string $type): FormatInterface |
||
{ |
{ |
||
$class = |
$class = "Format" . $type; |
||
if (!class_exists($class)) { |
|||
throw new Exception('Missing format class.'); |
|||
} |
|||
return new $class; |
return new $class; |
||
} |
} |
||
Line 167: | Line 174: | ||
try { |
try { |
||
$string = Factory::build( |
$string = Factory::build("String"); |
||
} catch ( |
} catch (Error $e) { |
||
echo $e->getMessage(); |
echo $e->getMessage(); |
||
} |
} |
||
try { |
try { |
||
$number = Factory::build( |
$number = Factory::build("Number"); |
||
} catch ( |
} catch (Error $e) { |
||
echo $e->getMessage(); |
echo $e->getMessage(); |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
== |
==Limits== |
||
There are three |
There are three limits associated with the use of the factory method. The first involves [[refactoring]] existing code; the other two involves extending a class. |
||
* The first |
* The first limit is that refactoring an existing class to use factories breaks existing clients. For example, if class Complex were a standard class, it might have many clients with code like:<syntaxhighlight lang="java">Complex c = new Complex(-1, 0);</syntaxhighlight> |
||
:Once |
:Once it is realized that two different factories are needed, the class is changed (to the code shown [[Factory (object-oriented programming)#Java|earlier]]). But since the constructor is now private, the existing client code no longer compiles. |
||
* The second |
* The second limit 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 |
* The third limit is that, if the class were to be extended (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 <code>StrangeComplex</code> extends <code>Complex</code>, then unless <code>StrangeComplex</code> provides its own version of all factory methods, the call <syntaxhighlight lang="csharp">StrangeComplex.FromPolar(1, Math.Pi);</syntaxhighlight> will yield an instance of <code>Complex</code> (the superclass) rather than the expected instance of the subclass. The [[reflective programming]] (reflection) features of some languages can avoid 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]]).<ref>{{cite journal |
All three problems could be alleviated by altering the underlying programming language to make factories first-class class members (see also [[Virtual class]]).<ref>{{cite journal |
||
⚫ | |||
| first = Ellen |
|||
|first1=Ellen |
|||
⚫ | |||
⚫ | |||
| |
|first2=Aino |
||
⚫ | |||
⚫ | |||
| |
|isbn=1-58113-005-8 |
||
| |
|title=How to preserve the benefits of design patterns |
||
| |
|pages=134–143 |
||
⚫ | |||
| |
|journal=Conference on Object Oriented Programming Systems Languages and Applications |
||
| |
|location=Vancouver, British Columbia, Canada |
||
| |
|publisher=ACM |
||
}}</ref> |
}}</ref> |
||
==Notes== |
==Notes== |
||
{{ |
{{Notelist}} |
||
==References== |
==References== |
||
{{ |
{{Reflist}} |
||
{{ |
{{Refbegin}} |
||
* {{Cite book | |
* {{Cite book |last1=Eric |first1=Freeman |last2=Robson |first2=Elisabeth |last3=Bates |first3=Bert |last4=Sierra |first4=Kathy |author4-link=Kathy Sierra |year=2009 |title=Head First Design Patterns |orig-year=2004 |url=http://shop.oreilly.com/product/9780596007126.do |series=[[Head First (book series)|Head First]] |publisher=O'Reilly |isbn=978-0-596-55656-3}} |
||
{{ |
{{Refend}} |
||
[[Category:Object-oriented programming]] |
[[Category:Object-oriented programming]] |
||
[[Category:Programming language comparisons]] |
|||
<!-- Hidden categories below --> |
|||
[[Category:Articles with example C Sharp code]] |
|||
[[Category:Articles with example Java code]] |
|||
[[Category:Articles with example PHP code]] |
|||
[[zh:工厂方法#工厂]] |
[[zh:工厂方法#工厂]] |
Latest revision as of 05:46, 5 October 2024
In object-oriented programming, a factory is an object for creating other objects; formally, it is a function or method that returns objects of a varying prototype or class[1] 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. The factory pattern is the basis for a number of related software design patterns.
Motive
[edit]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 one class, and by a specified process (class instantiation), while a factory can create objects by instantiating various classes, or by using other allocation means, 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 means.
A factory may be implemented in various ways. Most often it is implemented as a method, in which case it is called a factory method. Sometimes it is implemented as a function, in which case it is called a factory function. In some languages, constructors are factories. However, in most languages they are not, and constructors are invoked in a way that is idiomatic to the language, such as by using the keyword new
, while a factory has no special status and is invoked via an ordinary method call or function call. In these languages, a factory is an abstraction of a constructor, but not strictly a generalization, as constructors are not factories.
Terminology
[edit]Terminology differs as to whether the concept of a factory is a design pattern – in 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,[2][3] while others consider the concept a programming idiom,[4] 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 may be referred to as a simple factory.[4] In other contexts, particularly the Python language, the term factory is used, as in this article.[5] 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.[6] 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
[edit]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 use an existing object. More concretely, when a constructor is called, there is no object yet on which to dispatch.[b]
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.
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[7] 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 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
[edit]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 one instance.
Examples
[edit]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 f.obj is None:
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
[edit]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
[edit]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
[edit]Factories are used in various design patterns, specifically in creational patterns such as the Design pattern object library. 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 can create. These methods optionally accept parameters defining how the object is created, and then return the created object.
Applications
[edit]Factory objects are common in widget toolkits and software 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.[8]
Factories determine the concrete type of object to be created, and it is here that the object is created. As the factory only returns an abstract interface to the object, the client code does not know, and is unburdened by, the 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 data 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
[edit]Factories can be used when:
- Creating an object makes reuse impossible without significant duplication of code.
- Creating an object requires access to information or resources that should not be contained within the composing class.
- Managing the lifetime of generated objects must be centralized to ensure consistent behavior within an application.
Factories, specifically factory methods, are common in widget toolkits and software 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.[9] 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
[edit]Besides use in design patterns, factories, especially factory methods, have various benefits and variations.
Descriptive names
[edit]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, as illustrated by the following example in C#.
public class Complex
{
public double _real;
public double _imaginary;
public static Complex FromCartesian(double real, double imaginary)
{
return new Complex(real, imaginary);
}
public static Complex FromPolar(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.FromPolar(1, Math.PI);
When factory methods are used for disambiguation like this, the raw constructors are often made private to force clients to use the factory methods.
Encapsulation
[edit]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
[edit]public class ImageReaderFactory {
public static ImageReader createImageReader(ImageInputStreamProcessor iisp) {
if (iisp.isGIF()) {
return new GifReader(iisp.getInputStream());
}
else if (iisp.isJPEG()) {
return new JpegReader(iisp.getInputStream());
}
else {
throw new IllegalArgumentException("Unknown image type.");
}
}
}
PHP
[edit]class Factory
{
public static function build(string $type): FormatInterface
{
$class = "Format" . $type;
return new $class;
}
}
interface FormatInterface {}
class FormatString implements FormatInterface {}
class FormatNumber implements FormatInterface {}
try {
$string = Factory::build("String");
} catch (Error $e) {
echo $e->getMessage();
}
try {
$number = Factory::build("Number");
} catch (Error $e) {
echo $e->getMessage();
}
Limits
[edit]There are three limits associated with the use of the factory method. The first involves refactoring existing code; the other two involves extending a class.
- The first limit is that refactoring an existing class to use factories breaks existing clients. For example, if class Complex were a standard class, it might have many clients with code like:
Complex c = new Complex(-1, 0);
- Once it is realized that two different factories are needed, the class is changed (to the code shown earlier). But since the constructor is now private, the existing client code no longer compiles.
- The second limit 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 limit is that, if the class were to be extended (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
extendsComplex
, then unlessStrangeComplex
provides its own version of all factory methods, the callwill yield an instance ofStrangeComplex.FromPolar(1, Math.Pi);
Complex
(the superclass) rather than the expected instance of the subclass. The reflective programming (reflection) features of some languages can avoid 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).[10]
Notes
[edit]- ^ 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.
- ^ In languages where constructors are 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.
- ^ Constructors can be used anywhere factories can, since they are a special case.
- ^ This class is a subclass of
dict
, the built-in Python implementation of mappings or dictionaries. - ^ If optional keyword
new
is omitted.
References
[edit]- ^ Gamma, Erich (1994). Design Patterns. Addison-Wesley. pp. 18–19. ISBN 9780321700698.
- ^ Factory Pattern, OODesign.com
- ^ Factory Pattern, WikiWikiWeb
- ^ a b Chapter 4. The Factory Pattern: Baking with OO Goodness Archived 2017-03-11 at the Wayback Machine: The Simple Factory defined Archived 2014-02-19 at the Wayback Machine
- ^ 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
- ^ Factory Method, WikiWikiWeb
- ^ defaultdict objects
- ^ Feathers, Michael (October 2004). Working Effectively with Legacy Code. Upper Saddle River, New Jersey: Prentice Hall Professional Technical Reference. ISBN 978-0-13-117705-5.
- ^ Feathers, Michael (October 2004). Working Effectively with Legacy Code. Upper Saddle River, NJ: Prentice Hall Professional Technical Reference. ISBN 978-0-13-117705-5.
- ^ Agerbo, Ellen; Cornils, Aino (1998). "How to preserve the benefits of design patterns". Conference on Object Oriented Programming Systems Languages and Applications. Vancouver, British Columbia, Canada: ACM: 134–143. ISBN 1-58113-005-8.
- Eric, Freeman; Robson, Elisabeth; Bates, Bert; Sierra, Kathy (2009) [2004]. Head First Design Patterns. Head First. O'Reilly. ISBN 978-0-596-55656-3.