Factory method
The term factory method ( English factory method ) refers to a design pattern in the field of software development . The pattern describes how an object is created by calling a method instead of calling a constructor directly . It therefore belongs to the category of the generation pattern (Engl. Creational patterns ).
The term factory method can, however, be misleading as it describes both two slightly different design patterns and the method itself, depending on the speaker.
The pattern is one of the so-called GoF Design Patterns ( Gang of Four , see Gang of Four ).
Meaning of the term according to GoF
According to GoF , the factory method describes a pattern in which the interface for creating an object is an (abstract) method of a superclass. The concrete implementation of the creation of new objects does not take place in the superclass, but in subclasses derived from it, which implement the said abstract method.
The pattern thus describes the creation of product objects whose specific type is a sub-type of an abstract product class, which is determined by sub-classes of a producer class. It is sometimes called "virtual constructor" ( virtual constructor called).
Demarcation
In practice, the term factory method is often used simply for a static method that creates a new object, comparable to a constructor.
Example: Instead of
SomeObject o = new SomeObject();
is written using the static method colloquially known as the factory method:
SomeObject o = SomeObjectFactory.createNewInstance();
In this case, no use of subclasses or polymorphism is intended (for the method call itself) - however, the goal is usually that the generated, returned object (depending on the environment or on .createNewInstance(...)
given parameters) is from a subclass of SomeObject
.
However, this use of the term factory method is incorrect in the sense of the Gang of Four .
UML diagram
The following class diagram shows the four roles involved in the design pattern. KonkreterErzeuger
inherits the abstract factory method from Erzeuger
and implements it to KonkretesProdukt
produce, which in turn Produkt
implements.
actors
This Produkt
is the basic type (class or interface) for the product to be created. The Erzeuger
declares the factory method to create such a product and can contain a default implementation. Sometimes an implementation is specified for the factory method that creates a “standard product”.
KonkretesProdukt
implements the product interface. (So it's a specific sub-type of product). KonkreterErzeuger
overwrites the factory method in order to generate the specific products corresponding to it (e.g. by calling the constructor of a specific product class).
advantages
Factory methods decouple their callers from implementations of specific product classes, which means in particular that no new
operator is used in the calling class for instantiation . This is particularly valuable when software libraries develop further during the lifetime of an application - this means that instances of other classes can be created at a later point in time without the application having to change.
Many object-oriented programming languages dictate the name of the constructor. In contrast, a factory method (in the broader sense of the term) can have a more meaningful name and there can be several factory methods with different names and different semantics. For example, a method can create Color.createFromRGB()
a color object from RGB values , and a method can create Color.createFromHSV()
a color object from HSV values .
disadvantage
The use of this generation pattern amounts to subclassing. There must be a class of its own that can accept the class method for generation.
example
The following example illustrates the use of the GoF pattern in a software library for restaurant software.
A restaurant (producer) delivers meals (products). The basic procedure for delivering a meal is always the same: placing an order, preparing a meal, serving a meal. This can all be Restaurant
implemented in class , except for preparing the meal. The preparation (production) depends on the type of restaurant: One Pizzeria
(specific producer) creates pizzas (specific products), one Rostwurstbude
creates grilled sausages.
Restaurant
To do this MahlzeitLiefern()
, the class implements a method that delivers the meal, including the ordering and serving process. It uses an abstract method MahlzeitZubereiten()
that prepares (generates) the specific meal for the specific restaurant. MahlzeitZubereiten()
is the factory method and must be implemented accordingly for each specific restaurant.
This software library can be used for a new type of restaurant with its own menu of meals: A new class must be derived from Mahlzeit
and from Restaurant
, and the Restaurant
method of MahlzeitZubereiten()
the derived class must prepare (generate) the meal offered in this restaurant.
#include <iostream>
#include <string>
#include <memory>
// Produkt
class Mahlzeit {
};
// konkretes Produkt
class Pizza : public Mahlzeit {
public:
Pizza() {
std::cout << "Pizza gebacken." << std::endl;
}
};
// noch ein konkretes Produkt
class Rostwurst : public Mahlzeit {
public:
Rostwurst(const std::string& beilage) {
std::cout << "Rostwurst gebraten." << std::endl;
if (!beilage.empty()) {
std::cout << "Serviert mit " << beilage << std::endl;
}
}
};
// Erzeuger
class Restaurant {
protected:
std::shared_ptr<Mahlzeit> mahlzeit;
// Die abstrakte Factory-Methode, die von Erzeugern implementiert werden muss.
virtual void MahlzeitZubereiten() = 0;
virtual void BestellungAufnehmen() {
std::cout << "Ihre Bestellung bitte!" << std::endl;
}
virtual void MahlzeitServieren() {
std::cout << "Hier Ihre Mahlzeit. Guten Appetit!" << std::endl;
}
public:
// Diese Methode benutzt die Factory-Methode.
void MahlzeitLiefern() {
BestellungAufnehmen();
MahlzeitZubereiten(); // Aufruf der Factory-Methode
MahlzeitServieren();
}
};
// konkreter Erzeuger für konkretes Produkt "Pizza"
class Pizzeria : public Restaurant {
protected:
// Implementierung der abstrakten Methode der Basisklasse
virtual void MahlzeitZubereiten() {
mahlzeit = std::make_shared<Pizza>();
}
};
// konkreter Erzeuger für konkretes Produkt "Rostwurst"
class Rostwurstbude : public Restaurant {
protected:
// Implementierung der abstrakten Methode der Basisklasse
virtual void MahlzeitZubereiten() {
mahlzeit = std::make_shared<Rostwurst>("Pommes und Ketchup");
}
};
int main() {
Pizzeria daToni;
daToni.MahlzeitLiefern();
Rostwurstbude brunosImbiss;
brunosImbiss.MahlzeitLiefern();
}
use cases
The factory method (in the GoF meaning) is used if a class cannot or should not know the objects to be created by it, or if subclasses should determine which objects are to be created. Typical use cases are frameworks and class libraries . At GRASP , the factory method represents a solution to the goals of low coupling and high cohesion.
Virtual method in interface or class
The virtual method can be defined both in the interface or in the class (e.g. facade) that is otherwise responsible for objects of a type. Subclasses can then create specific types. Typical scenarios:
Create dependent objects
Examples:
- Java:
java.sql.Connection.createStatement()
- the generated statement refers to the connection and “lives in it”. - .NET:
System.Data.IDbConnection.CreateCommand()
- the generatedIDbCommand
refers to the connection and "lives in it".
Often the generated dependent objects have factory methods for dependent objects, e.g. B. has IDbCommand
a method CreateParameter()
. For this reason, classes with such factory methods cannot be understood as “factory classes” (with main responsibility “object creation”) - in contrast to the abstract factory .
Generation of independent objects via centralized "indexed constructors"
A method from a family of factory methods is called Dictionary
via an using an s Key
. Code snippet (with C # delegates instead of subclasses - the delegate type represents the Erzeuger
, each specific anonymous method one KonkretenErzeuger
):
delegate IFoo CreateFoo(IContext creationParameter);
static IDictionary<Key, CreateFoo> fooFactory = new Dictionary<Key, CreateFoo>();
// Statische Initialisierung:
fooFactory[key1] = cp => new FooForKey1(cp);
fooFactory[key2] = cp => new FooForKey2Or3(new Key2Child(cp));
fooFactory[key3] = cp => new FooForKey2Or3(new Key3Child(cp));
Call:
IFoo newObject = fooFactory[key](someContext);
Allows a compact, descriptive design of the object creation. Danger (especially if - for example in C # - direct reference to function calls in the dictionary) that the factory objects take on more responsibility.
"Static Factory Method"
Single static
method that returns an object of a type or sub-type. No virtual constructor - sense of the matter: Central, class-based access point for object creation analogous to new. Sometimes only requires introduction of a single class as a Factory Method Holder . Examples:
- Java:
java.util.Collections.singletonMap()
- Java:
javax.xml.parsers.DocumentBuilderFactory.newInstance()
Related design patterns
An abstract factory is generally implemented using factory methods.
Factory methods are typically called from template methods .
Factory methods are often found in singletons .
Web links
- Factory method in C # ( English )
- Factory method in Vala (German)
- Example for the factory method in Java (German)
- Factory method in Java (English)
- Factory method in Java and .NET (English)