11.4. Abstract Factory¶
EN: Abstract Factory
PL: Fabryka Abstrakcyjna
Type: object
The Abstract Factory pattern differs from the Factory Pattern in that it returns Factories, rather than objects of concrete class.
11.4.1. Pattern¶
Provide an interface for creating families of related objects
Factory Method is a method
Abstract Factory is an abstraction (interface)
Used for theme support (which generates buttons, inputs etc)

11.4.2. Problem¶
Violates Open/Close Principle
Hard to add a new theme
Easy to accidentally use Material widget inside of Flat theme block

from enum import Enum
#%% Interfaces
class Widget:
def render(self) -> None:
raise NotImplementedError
class Button(Widget):
pass
class Textbox(Widget):
pass
#%% Material Theme
class MaterialButton(Button):
def render(self) -> None:
print('Material Button')
class MaterialTextbox(Textbox):
def render(self) -> None:
print('Material Textbox')
#%% Flat Theme
class FlatButton(Button):
def render(self) -> None:
print('Flat Button')
class FlatTextbox(Textbox):
def render(self) -> None:
print('Flat Textbox')
#%% Main
class Theme(Enum):
MATERIAL = 1
FLAT = 2
class ContactForm:
def render(self, theme: Theme) -> None:
if self.theme == Theme.MATERIAL:
MaterialTextbox().render()
MaterialButton().render()
elif self.theme == Theme.FLAT:
FlatTextbox().render()
FlatButton().render()
11.4.3. Solution¶

#%% Interfaces
class Widget:
def render(self) -> None:
raise NotImplementedError
class Button(Widget):
pass
class Textbox(Widget):
pass
class WidgetFactory:
def create_button(self) -> Button:
raise NotImplementedError
def create_textbox(self) -> Textbox:
raise NotImplementedError
#%% Material Theme
class MaterialButton(Button):
def render(self) -> None:
print('Material Button')
class MaterialTextbox(Textbox):
def render(self) -> None:
print('Material Textbox')
class MaterialWidgetFactory(WidgetFactory):
def create_button(self) -> Button:
return MaterialButton()
def create_textbox(self) -> Textbox:
return MaterialTextbox()
#%% Ant Theme
class AntButton(Button):
def render(self) -> None:
print('Ant Button')
class AntTextbox(Textbox):
def render(self) -> None:
print('Ant Textbox')
class AntWidgetFactory(WidgetFactory):
def create_button(self) -> Button:
return AntButton()
def create_textbox(self) -> Textbox:
return AntTextbox()
#%% Main
class ContactForm:
def render(self, factory: WidgetFactory) -> None:
factory.create_textbox().render()
factory.create_button().render()
if __name__ == '__main__':
theme = MaterialWidgetFactory()
ContactForm().render(theme)