Pattern factory method test questions. Generative patterns. Classic implementation of the Factory Method pattern

1. Name: Factory Method

2. Tasks:

    The system must remain extensible by adding new types of objects. Using the new expression directly is not advisable because it can cause the code for creating objects with specific types to be scattered throughout the application. Then such operations as adding objects of new types to the system or replacing objects of one type with another will be difficult (more details in the section Generative Patterns). The Factory Method pattern allows the system to remain independent of both the process of generating objects and their types.

    It is known in advance when to create an object, but its type is unknown.

3. Solution:

To ensure that the system remains independent of different object types, the Factory Method pattern uses the mechanism of polymorphism - classes of all final types inherit from one abstract base class intended for polymorphic use. This base class defines a single interface through which the user will operate objects of final types.

To make it relatively easy to add new types to the system, the Factory Method pattern localizes the creation of objects of specific types in a special factory class. The methods of this class, through which objects of specific classes are created, are called factory methods.

The interface of factory methods is declared in an independent factory class, and their implementation is determined by specific subclasses of this class.

4. UML class diagram of the Factory Method pattern. Classic implementation

Product- the product itself. Designed to define the interface of objects created by the factory method;

ConcreteProduct(Computer) - specific products that participate in the scheme and are responsible for implementing the abstract class (interface) Product.

Creator is the creator, and his name speaks for itself. This object is intended to declare a factory method that returns an object of type Product.

ConcreteCreator- specific creator. Here everything is obvious: the specific implementation of the creator is engaged in returning a specific product. In our example, the concrete implementation of the creator is ComputerCreator.

The creator trusts its subclasses to implement a suitable specific product. That's the point Factory Method.

5. Example of Factory Method implementation:

The Product class is intended to define the interface of objects created by a factory method. This is like a basic shell for products. The product has a price, etc.

    abstract class Product

    public abstract decimal PurchasePrice( get; set;}

    public abstract decimal Price ( get; set;}

    public abstract string Description ( get; set;}

We create a class inherited from the Product class, which will encapsulate the logic of a specific product:

    class Computer: Product

    private decimal _purchase_price;

    private decimal _price;

    private string _description;

    public Computer( string _description, decimal _purchase_price,

    decimal _price)

    this._description = _description;

    this._purchase_price = _purchase_price;

    this._price = _price;

    public override string Description

    get { return _description; )

    set( _description = value; )

    public override decimal Price

    get { return _price; )

    set( _price = value; )

    public override decimal PurchasePrice

    get { return _purchase_price; )

    set( _purchase_price = value; )

Let's describe an abstract creator class that has a factory method.

    abstract class Creator

    public abstract Product FactoryMethod( string _description,

    decimal _purchase_price, decimal _price);

We create a specific class for the creator of a specific product (inherited from Creator). This class defines a method for the constructor of the Computer class (if there are several constructors, then each constructor has its own factory method):

    class ComputerCreator: Creator

    public override Product FactoryMethod( string _description,

    decimal _purchase_price, decimal _price)

    return new Computer(_description,_purchase_price,_price);

Client code:

    static void Main( string args)

    List ProductList = new List

    Creator creators = new Creator;

    creators = new ComputerCreator();

    foreach(Creator cr in creators)

    if(cr is ComputerCreator)

    productList.Add(cr.FactoryMethod("Laptop", 600, 800));

    foreach(Product pr in productList)

    Console.WriteLine("Object of class (0);\n" +

    "Description: (1);\n" +

    "Purchase price: (2);\n" +

    "Sell price: (3);\n",

    pr.GetType().Name,

  1. pr.PurchasePrice,

Program result:

6. Pros and cons of this pattern:

The most obvious disadvantage of the Factory Method is the need to create a Creator successor whenever you plan to get a new type of product (i.e. a new ConcreteProduct). And this, alas, cannot be avoided. But a similar problem exists in many generative patterns. The advantages include the ability to create objects more universally, without focusing on specific classes and using a common interface.

Factory Method is a creational pattern. This design pattern provides an interface for creating instances of a class. At the moment of creation, heirs can determine which class to instantiate.

In other words, the Factory delegates creating objects for descendants of the parent class. This allows you to use not specific classes in the program code, but manipulate abstract objects at a higher level.

The Factory design pattern is very common. Let's look at a small example in Java.

Introduction: Requirements for various kinds of software products are constantly growing. Reports on the execution of application operations should be generated in different forms: XML, HTML, text, etc. This is exactly the case when it is convenient to use the Factory pattern.

Solution: The AbstractWriter class will represent an abstraction for writing to some context (be it an XML document or a text file).

Public abstract class AbstractWriter ( public abstract void write(Object context); )

This class can have any number of descendants. Let's consider the ConcreteFileWriter and ConcreteXmlWriter subclasses for writing to a text file and DOM document, respectively:

Public class ConcreteFileWriter extends AbstractWriter ( public void write (Object context) ( // method body ) ) public class ConcreteXmlWriter extends AbstractWriter ( public void write (Object context) ( // method body ) )

To create the object we need, we can write the following Factory:

Import java.io.File; import org.w3c.dom.Document; public class FactoryMethod ( public AbstractWriter getWriter(Object object) ( AbstractWriter writer = null; if (object instanceof File) ( writer = new ConcreteFileWriter(); ) else if (object instanceof Document) ( writer = new ConcreteXmlWriter(); ) return writer ; ) )

In the text of the program, when creating a report, you need to pass a File object or DOM document to the getWriter function. As a result of executing the method, we will receive the desired object of the required level of abstraction.

Use the Factory pattern in the following cases:

  • the class has no information about what type of object it should create;
  • the class passes responsibility for creating objects to its descendants;
  • you need to create an object depending on the incoming data.

In one of the subsequent design articles we will look at the pattern Abstract Factory.

In the meantime, I will be happy to listen to your questions, remarks and comments.



Comments: 5

As far as I understand, the example (special thanks for the examples in the cycle about patterns) illustrates a parameterized factory, since a parameter is passed to the factory method, on the basis of which a specific AbstractWriter subclass is created. Meanwhile, the classic factory, as far as I understand, behaves somewhat differently: “a class is designed so that the objects it creates are specified by subclasses” (E. Gamma ‘Design Patterns’). That is, there must be several FactoryMethod heirs for each AbstractWriter heir, and the choice remains with the client which FactoryMethod implementation to choose. Did I understand correctly?

In fact, the example does not show the Factory Method at all, but the so-called Simple Factory (this is not even a design pattern, but simply a widely used technique). Danik wrote correctly that the FactoryMethod class must have descendants that actually override the factory method. At first glance it may seem that there is no difference, but the difference is huge. Read “Head First Design Patterns” or “Design Patterns For Dummies” and everything will become clear to you.

You're wrong. This is still a factory method. We read from Erich Gamma: “parameterized factory methods. This is another variation of the pattern that allows the factory method to create different types of products. The factory method is passed a parameter that identifies the type of object being created.

All objects produced by a factory method share a common Product interface. In the documents example, the Application class can support different kinds of documents. You are passing an extra parameter to the CreateDocument method, which determines what type of document needs to be created.”

So before expressing your opinion it would be a good idea to study the mat part

I didn’t understand something, how is this different from the pattern strategy?

Maybe I’m being clever too. antonin yorov The difference between a factory and a strategy is that a strategy allows you to dynamically determine the desired algorithm (that is, you can connect the desired interface subclass in runtime), while a factory has a method in the algorithm that returns an object.

Before reading, please review the following conventions and concepts. This article is updated with some frequency, so if you have read it before, it is not a fact that the data has not changed.

Refer to class generating patterns. They are used to define and maintain relationships between objects. Factory methods eliminate the need for the designer to build application-specific classes into the code.

Example

Suppose we create an XML parser that parses the provided file and converts it into a DOM tree. Let's call each element of this tree a node. While parsing the file, we will be faced with the task of generating new nodes, and we will write there something like this code:

Class Xml_Node() ( /*...*/ public function parse() ( /*...*/ $ChildNode = new Xml_Node(); /*...*/ ) /*...*/ )

What's bad about it? Let me give you this example: we want to build a structure of objects, a certain class, based on an XML file, in order to use it in the future, and we, in accordance with the principle “everything has already been written for you,” wanted to use the ready-made XML_Node class.

We are making our own successor XML_Node_Processor , and now we want to influence the file analysis process so that with a certain tag a certain class is instantiated (For the food tag - My_Food, for cow - My_Big_Orange_Cow). And when implementing as above, for this we will have to fully overload the parse method in order to copy-paste the code from the parent class by editing just one line of code. Agree, this is stupid.

The essence of the pattern

Possible implementation in PHP

Abstract class XML_Node_Abstract ( abstract function createNode($tag); ) class Xml_Node extends XML_Node_Abstract ( /*...*/ public function createNode($tag) ( return new Xml_Node(); ) /*...*/ public function parse () ( /*...*/ $ChildNode = $this -> createNode($Tag); /*..*/ ) ) class Xml_Node_Processor extends Xml_Node ( public function createNode($tag) ( switch($tag) ( case "food": return new My_Food(); case "cow": return new My_Big_Orange_Cow(); ) return parent::createNode($tag); ) ) class My_Food extends Xml_Node_Processor (); class My_Big_Orange_Cow extends Xml_Node_Processor();

Finally

  • In a factory method implementation not always you need an abstract creator class (XML_Node_Abstract). A specific instance can be used in its place. From this example we can remove XML_Node_Abstract and nothing will change
  • The result returned by the factory method must Always correspond to a given interface (in our case, the interface of the Xml_Node class)
  • A factory method can be a static function, and can be used to instantiate objects of a subclass
  • Factory method not necessary must return an object, it can also return a class. At the same time, all heirs and parents must also return the class.

Actually consists of factory methods

Added

Question

Didn't understand. The point is that in the parse method of the heirs, instances of them, and not the parent, are created?

Why not instead:

$ChildNode = new Xml_Node () ;

not to do:

$ChildNode = new static; ?

Answer

new static does not solve the problem that the factory method is supposed to solve. Its main task is to remove dependency from the code, dependence on a specific class. It would seem that what’s wrong with this? Nothing. Exactly until you need to extend the class, add some logic, or set up unit testing.

Imagine you have this code in several places:

$node = new Xml_Node(); $title = $node->getTitle();

The project manager comes to you and says that xml will come in two different formats. You might also think:

If ($this -> isFormatOne ()) ( $node = new Xml_Node (); ) else ( $node = new Xml_Node_Extended (); ) $title = $node -> getTitle ();

Then he comes again and says that there will now be 3,10,500 formats. With such an architecture, you will have to make changes to ALL occurrences of such code EVERY time. If you use a factory method, you will only have to change it, and creating an object will always look the same:

$node = $this -> createNode(); $title = $node -> getTitle();

I agree that the article is very chaotic and does not reveal all the beauty of this pattern, but I can tell you that this is one of the simplest and at the same time useful patterns. If you train yourself, instead of mindlessly generating an object, to delegate this operation to someone else, the problems will become much less.

Factory method is a generative design pattern that solves the problem of creating different products without specifying specific product classes.

A factory method specifies a method that should be used instead of calling the new operator to create product objects. Subclasses can override this method to change the type of products created.

Features of the pattern in Java

Complexity:

Popularity:

Applicability: The pattern can often be found in any Java code where flexibility is required when creating products.

The pattern is widely used in the Java standard libraries:

  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (Returns different singleton objects, depending on the protocol)
  • javax.xml.bind.JAXBContext#createMarshaller() and other similar methods.

Signs of using a pattern: A factory method can be defined by creation methods that return product objects through abstract types or interfaces. This allows you to override the types of products created in subclasses.

Production of cross-platform GUI elements

In this example, the products are buttons and the creator is a dialog.

Different types of dialogs have their own element types. Therefore, for each type of dialogue, we create our own subclass and override the factory method in it.

Each specific dialog will generate the buttons that correspond to it. At the same time, the basic dialog code will not break, since it works with products only through their common interface.

buttons

buttons/Button.java: Common button interface

package site.factory_method.example.buttons; /** * Common interface for all products. */ public interface Button ( void render(); void onClick(); )

buttons/HtmlButton.java: Specific button class

package site.factory_method.example.buttons; /** * Implementation of HTML buttons. */ public class HtmlButton implements Button ( public void render() ( System.out.println(" "); onClick(); ) public void onClick() ( System.out.println("Click! Button says - "Hello World!"); ) )

buttons/WindowsButton.java: Another class of buttons

package site.factory_method.example.buttons; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Implementation of native operating system buttons. */ public class WindowsButton implements Button ( JPanel panel = new JPanel(); JFrame frame = new JFrame(); JButton button; public void render() ( frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Hello World!"); label.setOpaque(true); label.setBackground(new Color(235, 233, 126)); label.setFont(new Font("Dialog", Font.BOLD, 44)); label.setHorizontalAlignment( SwingConstants.CENTER); panel.setLayout(new FlowLayout(FlowLayout.CENTER)); frame.getContentPane().add(panel); panel.add(label); onClick(); panel.add(button); frame.setSize (320, 200); frame.setVisible(true); onClick(); ) public void onClick() ( button = new JButton("Exit"); button.addActionListener(new ActionListener() ( public void actionPerformed(ActionEvent e) ( frame.setVisible(false); System.exit(0); ) )); ) )

factory

factory/Dialog.java: Basic dialogue

package site.factory_method.example..factory_method.example.buttons.Button; /** * The base class of the factory. Note that "factory" is just * an additional role for the class. It already has some business logic that * requires the creation of a variety of products. */ public abstract class Dialog ( public void renderWindow() ( // ... the rest of the dialog code... Button okButton = createButton(); okButton.render(); ) /** * Subclasses will override this method to create specific * product objects, different for each factory. */ public abstract Button createButton(); )

factory/HtmlDialog.java: Concrete class of dialogues

package site.factory_method.example..factory_method.example.buttons..factory_method.example.buttons.HtmlButton; /** * HTML dialog. */ public class HtmlDialog extends Dialog ( @Override public Button createButton() ( return new HtmlButton(); ) )

factory/WindowsDialog.java: Another class of dialogues

package site.factory_method.example..factory_method.example.buttons..factory_method.example.buttons.WindowsButton; /** * Dialog on operating system elements. */ public class WindowsDialog extends Dialog ( @Override public Button createButton() ( return new WindowsButton(); ) )

Demo.java: Client code

package site.factory_method..factory_method.example.factory..factory_method.example.factory.Html.factory_method.example.factory.WindowsDialog; /** * Demo class. This is where it all comes together. */ public class Demo ( private static Dialog dialog; public static void main(String args) ( configure(); runBusinessLogic(); ) /** * The application creates a specific factory depending on the configuration or * environment. */ static void configure () ( if (System.getProperty("os.name").equals("Windows 10")) ( dialog = new WindowsDialog(); ) else ( dialog = new HtmlDialog(); ) ) /** * Everything else client code interacts with the factory and products only * through a common interface, so it does not matter which factory was * created. */ static void runBusinessLogic() ( dialog.renderWindow(); ) )

OutputDemo.txt: Result with HtmlDialog factory

Click! Button says - "Hello World!"

Purpose of the Factory Method pattern

The system often needs to create objects of many different types. The Factory Method pattern can be useful in solving the following problems:

  • The system must remain extensible by adding new types of objects. Using the new expression directly is not advisable because it can cause the code for creating objects with specific types to be scattered throughout the application. Then such operations as adding new types of objects to the system or replacing objects of one type with another will be difficult (for more details, see the Generating Patterns section). The Factory Method pattern allows the system to remain independent of both the process of generating objects and their types.
  • It is known in advance when to create an object, but its type is unknown.

Description of the Factory Method pattern

To ensure that the system remains independent of different object types, the Factory Method pattern uses the mechanism of polymorphism - classes of all final types inherit from one abstract base class intended for polymorphic use. This base class defines a single interface through which the user will operate objects of final types.

To make it relatively easy to add new types to the system, the Factory Method pattern localizes the creation of objects of specific types in a special factory class. The methods of this class, through which objects of specific classes are created, are called factory methods. There are two varieties of the Factory Method pattern:

Generic constructor , when a static factory method is defined in the same polymorphic base class from which the derived classes of all types created in the system inherit. The type identifier of the object being created must be passed as a parameter to this method.

The classic version of the factory method , when the interface of factory methods is declared in an independent factory class, and their implementation is determined by specific subclasses of this class.

Implementation of the Factory Method pattern

Let's consider both options for implementing the Factory Method pattern using the example of the process of generating military characters for our strategic game. Its detailed description can be found in the section Generative Patterns. To simplify the demo code, we will create military characters for some abstract army without taking into account the characteristics of the warring parties.

Implementation of the Factory Method pattern based on a generic constructor

// #include #include enum Warrior_ID ( Infantryman_ID=0, Archer_ID, Horseman_ID ); // Hierarchy of game character classes class Warrior ( public: virtual void info() = 0; virtual ~Warrior() () // Parameterized static factory method static Warrior* createWarrior(Warrior_ID id); ); class Infantryman: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; } }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; } }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; } }; // Реализация параметризированного фабричного метода Warrior* Warrior::createWarrior(Warrior_ID id) { Warrior * p; switch (id) { case Infantryman_ID: p = new Infantryman(); break; case Archer_ID: p = new Archer(); break; case Horseman_ID: p = new Horseman(); break; default: assert(false); } return p; }; // Создание объектов при помощи параметризированного фабричного метода int main() { vectorv; v.push_back(Warrior::createWarrior(Infantryman_ID)); v.push_back(Warrior::createWarrior(Archer_ID)); v.push_back(Warrior::createWarrior(Horseman_ID)); for(int i=0; i info(); // ... )

The presented version of the Factory Method pattern is popular due to its simplicity. In it, the static factory method createWarrior() is defined directly in the polymorphic Warrior base class. This factory method is parameterized, meaning that to create an object of a certain type, the corresponding type identifier is passed to createWarrior().

From the point of view of the “purity” of object-oriented code, this option has the following disadvantages:

  • Since the code for creating objects of all possible types is concentrated in the static factory method of the Warrior class, the base Warrior class has knowledge of all classes derived from it, which is atypical for an object-oriented approach.
  • Using a switch statement like this (as in the code for the createWarrior() factory method) is also discouraged in object-oriented programming.

These disadvantages are absent in the classic implementation of the Factory Method pattern.

Classic implementation of the Factory Method pattern

// #include #include // Hierarchy of game character classes class Warrior ( public: virtual void info() = 0; virtual ~Warrior() () ); class Infantryman: public Warrior ( public: void info() ( cout<< "Infantryman" << endl; }; }; class Archer: public Warrior { public: void info() { cout << "Archer" << endl; }; }; class Horseman: public Warrior { public: void info() { cout << "Horseman" << endl; }; }; // Фабрики объектов class Factory { public: virtual Warrior* createWarrior() = 0; virtual ~Factory() {} }; class InfantryFactory: public Factory { public: Warrior* createWarrior() { return new Infantryman; } }; class ArchersFactory: public Factory { public: Warrior* createWarrior() { return new Archer; } }; class CavalryFactory: public Factory { public: Warrior* createWarrior() { return new Horseman; } }; // Создание объектов при помощи фабрик объектов int main() { InfantryFactory* infantry_factory = new InfantryFactory; ArchersFactory* archers_factory = new ArchersFactory ; CavalryFactory* cavalry_factory = new CavalryFactory ; vectorv; v.push_back(infantry_factory->createWarrior()); v.push_back(archers_factory->createWarrior()); v.push_back(cavalry_factory->createWarrior()); for(int i=0; i info(); // ... )

The classic version of the Factory Method pattern uses the idea of ​​a polymorphic factory. The polymorphic base class Factory, specifically dedicated to creating objects, declares the interface of the createWarrior() factory method, and its derived classes implement it.

The presented version of the Factory Method pattern is the most common, but not the only one. The following variations are possible:

  • The Factory class has a default implementation of the createWarrior() factory method.
  • The createWarrior() factory method of the Factory class is parameterized by the type of the object being created (like the simple Factory Method presented earlier) and has a default implementation. In this case, Factory-derived classes are only needed to define the non-standard behavior of createWarrior() .

Results of applying the Factory Method pattern

Advantages of the Factory Method pattern

  • Creates objects of different types, allowing the system to remain independent both from the creation process itself and from the types of objects being created.

Disadvantages of the Factory Method pattern

  • In the case of the classic version of the pattern, even to generate a single object, it is necessary to create a corresponding factory