Home [Design Patterns] Factory Method Pattern
Post
Cancel

[Design Patterns] Factory Method Pattern

Definition

The factory method pattern defines an interface for creating an object but lets its subclasses decide the instantiate logic. The factory method enables the class to (the end result) defer its creation to subclasses (the factory).

Scenario

We have to instantiate the class at some point; sometimes, there is some logic behind deciding what to create. For example, the class (the end results we want) has complex properties, like different parameters or options. And for different schemas, we might want to have different logic to decide what class to create.

We can encapsulate the instantiation process somewhere to make it uniform everywhere.

Class Diagram

Factory Method Pattern Factory Method Pattern

CreateAnimal method in IAnimalFactory will make the decision of what we are going to create.

We use polymorphism in IAnimal so that animals (Cat, Dog, Duck) are grouped together, and a factory (RandomFactory and SimpleFactory) can create either one of them. IAnimalFactory uses polymorphism for the same reason, such that we can easily swap different factories and have different creation logic.

If we only have a concrete factory (no IAnimalFactory) to create products (Cat, Dog, Duck), then this is called Simple Factory Method.

Used Cases

  • Instead of creating objects using new, we can pass the factory.
  • It turns how to create something into a class (factory). We can have factories targeting different objects and have various combinations of them, so we can avoid class explosion.
  • Creating game levels by passing in different parameters to the factory. Those parameters might be associated with an obstacle’s size and speed, so the factory knows how to create obstacles for that level during game time.

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// factory_method.h
#ifndef __FACTORY_METHOD_H__
#define __FACTORY_METHOD_H__

#include <memory>
#include <string>

class IAnimal {
protected:
    std::string name_;

public:
    IAnimal(const std::string&& name) : name_(name) {}
    virtual void PrintName();
};

class Cat : public IAnimal {
public:
    Cat() : IAnimal("cat") {}
};

class Dog : public IAnimal {
public:
    Dog() : IAnimal("dog") {}
};

class Duck : public IAnimal {
public:
    Duck() : IAnimal("duck") {}
};

class IAnimalFactory {
public:
    virtual std::unique_ptr<IAnimal> CreateAnimal() = 0;
};

class RandomFactory : public IAnimalFactory {
public:
    RandomFactory();
    std::unique_ptr<IAnimal> CreateAnimal() override;
};

class SimpleFactory : public IAnimalFactory {
private:
    std::string target_animal_;

public:
    SimpleFactory(const std::string&& animal) : target_animal_(animal) {}
    SimpleFactory() : target_animal_("cat") {}
    std::unique_ptr<IAnimal> CreateAnimal() override;
};

#endif  //__FACTORY_METHOD_H__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// factory_method.cpp
#include "factory_method.h"

#include <cstdlib>
#include <ctime>
#include <iostream>

void IAnimal::PrintName() { std::cout << "Animal name:" << name_ << std::endl; }

RandomFactory::RandomFactory() { srand(time(nullptr)); }

std::unique_ptr<IAnimal> RandomFactory::CreateAnimal() {
    switch (rand() % 3 + 1) {
        case 1:
            return std::make_unique<Cat>();
        case 2:
            return std::make_unique<Dog>();
        case 3:
            return std::make_unique<Duck>();
    }
}

std::unique_ptr<IAnimal> SimpleFactory::CreateAnimal() {
    if (target_animal_ == "cat") {
        return std::make_unique<Cat>();
    } else if (target_animal_ == "dog") {
        return std::make_unique<Dog>();
    } else if (target_animal_ == "duck") {
        return std::make_unique<Duck>();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// main.cpp
#include <iostream>

#include "factory_method.h"

int main() {
    {
        std::unique_ptr<IAnimalFactory> animal_factory = std::make_unique<SimpleFactory>("duck");
        std::unique_ptr<IAnimal> animal_ptr = animal_factory->CreateAnimal();
        animal_ptr->PrintName();
    }
    return 0;
}

Reference

This post is licensed under CC BY 4.0 by the author.