(Credit: Concepts explained here are based on a book, “増補改訂版Java言語で学ぶデザインパターン入門”.)
A factory method pattern is a pattern in which a superclass describes how an instance should be created but does not define its internal structure. Its detailed structure is written in a subclass.
Let’s create a program. In this program, a framework package is used for creating an instance and a idcard package is used for adding an internal structure or details of that class such as method and attributes.
First class in this program is a Product class. This class only defines a method, use, that is implemented in its subclass. This class basically defines a product as something you can ‘use’.
# product.py
from abc import ABC, abstractmethod
class Product(ABC):
@abstractmethod
def use(self):
pass
Next is a Factory class. This class defines three methods; create, create_product and register_product. Create is a class that creates and registers an instance of a product. create_product is a method to create an instance of a Product class. register_product is a method that registers an owner of a created product. Both create_product and register_product are abstract methods so they are implemented in its subclass.
# factory.py
from abc import ABC, abstractmethod
from framework import Product
class Factory(ABC):
def create(self, owner):
p = self._create_product(owner)
self._register_product(p)
assert isinstance(p, Product)
return p
@abstractmethod
def _create_product(self, owner):
pass
@abstractmethod
def _register_product(self, product):
pass
Let’s move on to an idcard package. Let’s create an actual product, an id card.
# idcard.py
from framework import Product
class IDCard(Product):
def __init__(self, owner):
print(f"Create {owner}'s card. '")
self.owner = owner
def use(self):
print(f"Use {self.owner}'s card. '")
def get_owner(self):
return self.owner
Next class is a IDCardFactory class which has two methods: create_product and register_product. create_product method creates an instance of an IDCard class. register_product registers an owner of a created product.
# idcard_factory.py
from framework import Product
from framework import Factory
from idcard import IDCard
class IDCardFactory(Factory):
_owners = []
def _create_product(self, owner):
return IDCard(owner)
def _register_product(self, product):
self._owners.append(product.get_owner())
def get_owners(self):
return self._owners
Let’s run this program.
# main.py
from framework import Product, Factory
from idcard import IDCard, IDCardFactory
def main():
factory = IDCardFactory()
card1 = factory.create("Kenta")
card2 = factory.create("test-user")
card3 = factory.create("Mr X")
card1.use()
card2.use()
card3.use()
print(f"Registered owners are {factory.get_owners()}")
if __name__ == "__main__":
main()
# Result of running main.py
Create Kenta's card. '
Create test-user's card. '
Create Mr X's card. '
Use Kenta's card. '
Use test-user's card. '
Use Mr X's card. '
Registered owners are ['Kenta', 'test-user', 'Mr X']
One benefit of a Factory method pattern: You only need to modify a concrete package which is an idcard package in this program without modifying a framework package. Since a framework package does not depend on a concrete package or a package that makes a structure of a product, modifying or adding a new product without affecting a framework package is possible. For example, it is possible to create a computer package and to generates and to register a computer object without touching source code used in a framework package.