Factory method

from Wikipedia, the free encyclopedia

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. KonkreterErzeugerinherits the abstract factory method from Erzeugerand implements it to KonkretesProduktproduce, which in turn Produktimplements.

Class diagram of the roles involved in the pattern.

actors

This Produktis the basic type (class or interface) for the product to be created. The Erzeugerdeclares 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”.

KonkretesProduktimplements the product interface. (So ​​it's a specific sub-type of product). KonkreterErzeugeroverwrites 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 newoperator 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 Restaurantimplemented 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 Rostwurstbudecreates grilled sausages.

RestaurantTo 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 Mahlzeitand from Restaurant, and the Restaurantmethod 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 generated IDbCommandrefers to the connection and "lives in it".

Often the generated dependent objects have factory methods for dependent objects, e.g. B. has IDbCommanda 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 Dictionaryvia 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 staticmethod 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