Factory of Factories pattern

This example demonstrate implementation of “Factory of Factories” pattern. Main idea of this pattern is about creation of a Factory that creates another Factory and mix additional arguments to it.

Listing of data.py, demonstrates sample classes structure:

 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
"""Sample data classes."""


class SqlAlchemyDatabaseService:
    """Database service of an entity."""

    def __init__(self, session, base_class):
        """Initialize object."""
        self.session = session
        self.base_class = base_class


class TokensService:
    """Tokens service."""

    def __init__(self, id_generator, database):
        """Initialize object."""
        self.id_generator = id_generator
        self.database = database


class Token:
    """Token entity."""


class UsersService:
    """Users service."""

    def __init__(self, id_generator, database):
        """Initialize object."""
        self.id_generator = id_generator
        self.database = database


class User:
    """User entity."""


# Sample objects
session = object()
id_generator = object()

Listing of factory_of_factories.py, demonstrates “Chained Factories” pattern and provide some explanation:

 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""`Factory of Factories` pattern."""

from dependency_injector import providers

from data import (
    id_generator,
    session,
    SqlAlchemyDatabaseService,
    TokensService,
    Token,
    UsersService,
    User,
)


# "Factory of Factories" pattern

database_factory = providers.Factory(
    providers.Factory,
    SqlAlchemyDatabaseService,
    session=session,
)

tokens = providers.Factory(
    TokensService,
    id_generator=id_generator,
    database=database_factory(base_class=Token),
)

users = providers.Factory(
    UsersService,
    id_generator=id_generator,
    database=database_factory(base_class=User),
)

tokens_service = tokens()
assert tokens_service.database.base_class is Token

users_service = users()
assert users_service.database.base_class is User

# Explanation & some more examples

# 1. Keyword arguments of upper level factory are added to lower level factory
factory_of_dict_factories = providers.Factory(
    providers.Factory,
    dict,
    arg1=1,
)
dict_factory = factory_of_dict_factories(arg2=2)
print(dict_factory())  # prints: {'arg1': 1, 'arg2': 2}

# 2. Keyword arguments of upper level factory have priority
factory_of_dict_factories = providers.Factory(
    providers.Factory,
    dict,
    arg1=1,
)
dict_factory = factory_of_dict_factories(arg1=2)
print(dict_factory())  # prints: {'arg1': 2}

# 3. Keyword arguments provided from context have most priority
factory_of_dict_factories = providers.Factory(
    providers.Factory,
    dict,
    arg1=1,
)
dict_factory = factory_of_dict_factories(arg1=2)
print(dict_factory(arg1=3))  # prints: {'arg1': 3}