The Factory Method

Contents[Show]

The classic book "Design Patterns: Elements of Reusable Object-Oriented Software" has 23 patterns. They are ordered by intent: creational, structural, and behavioral patterns. Today,  I focus on the creational pattern Factory Method.

 CreationalPatterns

Five patterns in the book "Design Patterns: Elements of Reusable Object-Oriented Software" (short Design Patterns) are creational, seven structural, and the remaining one behavioral. First of all, what does this mean?

  • Creational patterns deal with object creation in a well-defined way.
  • Structural patterns provide mechanisms to organize class and objects for larger structures.
  • Behavioral patterns deal with communication patterns between objects.

Before I start with the creational patterns,  I want to make a short disclaimer.

Short Disclaimer

I present about half of the 23 design patterns. For the remaining ones, I only provide a fact sheet. The selection of the presented design pattern is based on two points.

  1. Which patterns did I encounter most often as a software developer in the last twenty years?
  2. Which patterns are still in use?

My explanation of the presented design patterns is intentionally concise. My idea is to present the key principle of a pattern and present them from a C++ point of view. If you want to have more details, there is excellent documentation available. Here are a few choices:

Creational patterns deal with object creation. Let's dive deeper.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

Creational Patterns

I will write about two of the five creational patterns: Factory Method and Singleton. I know, I know the Singleton could also be regarded as an Anti-Pattern. In a later post, I will discuss the Singleton in more depth. Let's start with the Factory Method:

Factory Method

Here are the facts:

Purpose

The factory method defines an interface to create a single object but lets subclasses decide which objects to create. The interface can provide a default implementation for creating objects.

Also known as

Virtual constructor

Use Case

  • A class does not know what kind of objects to create
  • Subclasses decide what object to create
  • Classes delegate the creation of objects to subclasses

Example

Each container of the Standard Template Library has eight factory functions to generate various iterators.

  • begin, cbegin: returns an iterator to the beginning of the container
  • end, cend: returns an iterator to the end of the container
  • rbegin, crbegin: returns a reverse iterator to the beginning of the container
  • rend, crend: returns a reverse iterator to the end of the container
The factory functions starting with c, return constant iterators.

Structure

FactoryMethod

 

Product

  • Objects created by factoryMethod.

Concrete Product

  • Implements the interface

Creator

  • Declares the factory method
  • Calls the factory method

Concrete Creator

  • Overwrites the factory method

The Creator does not instantiate the Concrete Product. It calls its virtual member function factoryMethod. Consequentially, the Concrete Product is created by the Concrete Creator, and the object creation is independent of the Creator.

This pattern is also known as a virtual constructor.

Virtual Constructor

Honestly, the name virtual constructor is misleading. We don't have a virtual constructor in C++, but we have virtual construction to simulate a virtual constructor.

Assume you have a class hierarchy with an interface class Window and two implementation classes, DefaultWindow and FancyWindow.

// Product
class Window { 
 public: 
    virtual ~Window() {};
};

// Concrete Products 
class DefaultWindow: public Window {};

class FancyWindow: public Window {};

 

Now, you want to create a new Window based on an existing one. This means that when you put an instance of DefaultWindow or FancyWindow inside the factory function getNewWindow, it should return an instance of the same class.

Classically, the factory method is implemented using an enum and a factory function. Here is the first try:

// factoryMethodClassic.cpp

#include <iostream>

enum class WindowType {                                          // (5)
    DefaultWindow,
    FancyWindow
};

// Product
class Window { 
 public: 
    virtual ~Window() {};
    virtual WindowType getType() const = 0;
    virtual std::string getName() const = 0;
};

// Concrete Products 
class DefaultWindow: public Window { 
 public:
    WindowType getType() const override {
        return WindowType::DefaultWindow;
    }
    std::string getName() const override { 
        return "DefaultWindow";
    }
};

class FancyWindow: public Window {
 public: 
     WindowType getType() const override {
        return WindowType::FancyWindow;
    }
    std::string getName() const override { 
        return "FancyWindow";
    }
};

// Concrete Creator or Client
Window* getNewWindow(Window* window) {                           // (1)
    switch(window->getType()){                                   // (4)
    case WindowType::DefaultWindow:
        return new DefaultWindow();
        break;
    case WindowType::FancyWindow:
        return new FancyWindow();
        break;
    }
    return nullptr;
}
  
int main() {

    std::cout << '\n';

    DefaultWindow defaultWindow;
    FancyWindow fancyWindow;

    const Window* defaultWindow1 = getNewWindow(&defaultWindow); // (2)
    const Window* fancyWindow1 = getNewWindow(&fancyWindow);     // (3)

    std::cout << defaultWindow1->getName() << '\n';
    std::cout << fancyWindow1->getName() << '\n';
  
    delete defaultWindow1;
    delete fancyWindow1;

    std::cout << '\n';
  
}

 

The factory function in line (1) decides, based on the incoming Window, which Window (lines 2 and 3) should be created. It uses window->getType() (line 4) to get the right Window type. The WindowType is an enumeration.

Finally, here is the output of the program:

factoryMethodClassic

Honestly, I don't like this solution for the following reasons:

  1. When my application should support, I would have to extend the enumeration WindowType and the switch statement.
  2. The switch statement becomes more and more difficult to maintain if I add new WindowType's.
  3. The code is too complicated. This is mainly due to the switch statement.

Let me replace the switch statement with a virtual dispatch. Additionally, I also want to clone the existing Window's.

// factoryMethod.cpp

#include <iostream>

// Product
class Window{ 
 public: 
    virtual Window* create() = 0;                       // (1)
    virtual Window* clone() = 0;                        // (2)
    virtual ~Window() {};
};

// Concrete Products 
class DefaultWindow: public Window { 
    DefaultWindow* create() override { 
        std::cout << "Create DefaultWindow" << '\n';
        return new DefaultWindow();
    } 
     DefaultWindow* clone() override { 
        std::cout << "Clone DefaultWindow" << '\n';
        return new DefaultWindow(*this);
    } 
};

class FancyWindow: public Window { 
    FancyWindow* create() override { 
        std::cout << "Create FancyWindow" << '\n';
        return new FancyWindow();
    } 
    FancyWindow* clone() override { 
        std::cout << "Clone FancyWindow" << '\n';
        return new FancyWindow(*this);                  // (5)
    } 
};

// Concrete Creator or Client                             
Window* createWindow(Window& oldWindow) {               // (3)
    return oldWindow.create();
}

Window* cloneWindow(Window& oldWindow) {                // (4)    
    return oldWindow.clone();
}
  
int main() {

    std::cout << '\n';

    DefaultWindow defaultWindow;
    FancyWindow fancyWindow;
  
    const Window* defaultWindow1 = createWindow(defaultWindow);
    const Window* fancyWindow1 = createWindow(fancyWindow);
    
    const Window* defaultWindow2 = cloneWindow(defaultWindow);
    const Window* fancyWindow2 = cloneWindow(fancyWindow);
  
    delete defaultWindow1;
    delete fancyWindow1;
    delete defaultWindow2;
    delete fancyWindow2;

    std::cout << '\n';
  
}

 

Window supports now two ways to create new ones: a default constructed Window with the member function create (line 1) and a copy constructed Window with the member function clone (line 2). The subtle difference is that the constructor takes the this pointer in the member function clone. (line The factory functions createWindow (line 3) and cloneWindow (line 4) dispatch on the dynamic type.

The output of the program is promising. Both member functions create and clone display the name of the object they create.

factoryMethodPointer 

By the way. It is fine that the virtual member functions create and clone member functions of the DefaultWindow and the FancyWindow are private, because you use them via the Window interface. In the interface, both member function are public.

What's Next?

Am I'm done with the factory method? NO! The program factoryMethod.cpp has two serious issues. ownership semantic and slicing. Let me write more about it in my next post.

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

 

 

 

 

 

Stay Informed about my Mentoring

 

Mentoring

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 2161

Yesterday 4344

Week 39039

Month 19285

All 12097494

Currently are 151 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments