10.3. Factory Method¶
10.3.1. Rationale¶
EN: Factory Method
PL: Metoda wytwórcza
Type: class
10.3.2. Use Cases¶
10.3.3. Design¶
10.3.4. Implementation¶
class Setosa:
pass
class Versicolor:
pass
class Virginica:
pass
def iris_factory(species):
if species == 'setosa':
return Setosa
elif species == 'versicolor':
return Versicolor
elif species == 'virginica':
return Virginica
else:
raise NotImplementedError
if __name__ == '__main__':
iris = iris_factory('setosa')
print(iris)
# <class '__main__.Setosa'>
iris = iris_factory('virginica')
print(iris)
# <class '__main__.Virginica'>
iris = iris_factory('arctica')
print(iris)
# Traceback (most recent call last):
# NotImplementedError
class Setosa:
pass
class Versicolor:
pass
class Virginica:
pass
def iris_factory(species):
cls = {
'setosa': Setosa,
'versicolor': Versicolor,
'virginica': Virginica,
}.get(species, None)
if not cls:
raise NotImplementedError
else:
return cls
if __name__ == '__main__':
iris = iris_factory('setosa')
print(iris)
# <class '__main__.Setosa'>
iris = iris_factory('virginica')
print(iris)
# <class '__main__.Virginica'>
iris = iris_factory('arctica')
print(iris)
# Traceback (most recent call last):
# NotImplementedError
class Setosa:
pass
class Virginica:
pass
class Versicolor:
pass
def iris_factory(species):
try:
classname = species.capitalize()
return globals()[classname]
except KeyError:
raise NotImplementedError
if __name__ == '__main__':
iris = iris_factory('setosa')
print(iris)
# <class '__main__.Setosa'>
iris = iris_factory('virginica')
print(iris)
# <class '__main__.Virginica'>
iris = iris_factory('arctica')
print(iris)
# Traceback (most recent call last):
# NotImplementedError
class PDF:
pass
class TXT:
pass
class File:
def __new__(cls, *args, **kwargs):
filename, extension = args[0].split('.')
if extension == 'pdf':
return PDF()
elif extension == 'txt':
return TXT()
if __name__ == '__main__':
file = File('myfile.pdf')
print(file)
# <__main__.PDF object at 0x...>
file = File('myfile.txt')
print(file)
# <__main__.TXT object at 0x...>
from abc import ABCMeta, abstractproperty
class Document(metaclass=ABCMeta):
@abstractproperty
@property
def _extension(self):
return
def __new__(cls, filename, *args, **kwargs):
name, extension = filename.split('.')
for cls in Document.__subclasses__():
if cls._extension == extension:
return super().__new__(cls)
else:
raise NotImplementedError('File format unknown')
class PDF(Document):
_extension = 'pdf'
class Txt(Document):
_extension = 'txt'
class Word(Document):
_extension = 'docx'
if __name__ == '__main__':
file = Document('myfile.txt')
print(type(file))
# <class '__main__.Txt'>
file = Document('myfile.pdf')
print(type(file))
# <class '__main__.PDF'>
from abc import ABCMeta, abstractproperty, abstractmethod
from dataclasses import dataclass
@dataclass
class ConfigParser(metaclass=ABCMeta):
_filename: str
@abstractproperty
@property
def _extension(self):
pass
def show(self):
content = self.__read()
return self._parse(content)
@abstractmethod
def _parse(self, content: str) -> dict:
return NotImplementedError
def __read(self):
with open(self._filename) as file:
return file.read()
def __new__(cls, filename, *args, **kwargs):
_, extension = filename.split('.')
for parser in cls.__subclasses__():
if parser._extension == extension:
instance = super().__new__(parser)
instance.__init__(filename)
return instance
else:
raise NotImplementedError('Parser for given file type not found')
class ConfigParserINI(ConfigParser):
_extension = 'ini'
def _parse(self, content: str) -> dict:
print('Parsing INI file')
class ConfigParserCSV(ConfigParser):
_extension = 'csv'
def _parse(self, content: str) -> dict:
print('Parsing CSV file')
class ConfigParserYAML(ConfigParser):
_extension = 'yaml'
def _parse(self, content: str) -> dict:
print('Parsing YAML file')
class ConfigFileJSON(ConfigParser):
_extension = 'json'
def _parse(self, content: str) -> dict:
print('Parsing JSON file')
class ConfigFileXML(ConfigParser):
_extension = 'xml'
def _parse(self, content: str) -> dict:
print('Parsing XML file')
if __name__ == '__main__':
# iris.csv or *.csv, *.json *.yaml...
# filename = input('Type filename: ')
config = ConfigParser('/tmp/myfile.json')
config.show()
import os
class HttpClientInterface:
def GET(self):
raise NotImplementedError
def POST(self):
raise NotImplementedError
class GatewayLive(HttpClientInterface):
def GET(self):
print('Execute GET request over network')
return ...
def POST(self):
print('Execute POST request over network')
return ...
class GatewayStub(HttpClientInterface):
def GET(self):
print('Returning stub GET')
return {'firstname': 'Mark', 'lastname': 'Watney'}
def POST(self):
print('Returning stub POST')
return {'status': 200, 'reason': 'OK'}
class HttpGatewayFactory:
def __new__(cls, *args, **kwargs):
if os.getenv('ENVIRONMENT') == 'production':
return GatewayLive()
else:
return GatewayStub()
if __name__ == '__main__':
os.environ['ENVIRONMENT'] = 'testing'
client = HttpGatewayFactory()
result = client.GET()
# Returning stub GET
result = client.POST()
# Returning stub POST
os.environ['ENVIRONMENT'] = 'production'
client = HttpGatewayFactory()
result = client.GET()
# Execute GET request over network
result = client.POST()
# Execute POST request over network
from abc import ABCMeta, abstractmethod
class Path(metaclass=ABCMeta):
def __new__(cls, path, *args, **kwargs):
if path.startswith(r'C:\Users'):
instance = object.__new__(WindowsPath)
if path.startswith('/home'):
return object.__new__(LinuxPath)
if path.startswith('/Users'):
return object.__new__(macOSPath)
instance.__init__(path)
return instance
def __init__(self, filename):
self.filename = filename
@abstractmethod
def dir_create(self): pass
@abstractmethod
def dir_list(self): pass
@abstractmethod
def dir_remove(self): pass
class WindowsPath(Path):
def dir_create(self):
print('create directory on ')
def dir_list(self):
print('list directory on ')
def dir_remove(self):
print('remove directory on ')
class LinuxPath(Path):
def dir_create(self):
print('create directory on ')
def dir_list(self):
print('list directory on ')
def dir_remove(self):
print('remove directory on ')
class macOSPath(Path):
def dir_create(self):
print('create directory on ')
def dir_list(self):
print('list directory on ')
def dir_remove(self):
print('remove directory on ')
if __name__ == '__main__':
file = Path(r'C:\Users\MWatney\myfile.txt')
print(type(file))
# <class '__main__.WindowsPath'>
file = Path(r'/home/mwatney/myfile.txt')
print(type(file))
# <class '__main__.LinuxPath'>
file = Path(r'/Users/mwatney/myfile.txt')
print(type(file))
# <class '__main__.macOSPath'>