Card 07/ 08
Practice: Light and Dark Themes for a Widget Kit
Buttons, checkboxes and sliders, in a light family and a dark one.
A widget kit with themes is a classic Abstract Factory, and this exercise asks you to apply the pattern to one and then price the two changes the pattern treats differently. A settings screen shows a button, a checkbox and a slider. The kit has a light theme and a dark theme, and the screen must never show a light button beside a dark slider.
- Name the abstract factory, its creation methods, and the concrete factories.
- Write
settings_screen(theme)so that it never names a light or dark class. - Count the new and edited classes for adding a toggle switch, a fourth kind of widget.
- Count them for adding a high-contrast theme instead.
Show a solution
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def render(self) -> str: ...
class Checkbox(ABC):
@abstractmethod
def render(self) -> str: ...
class Slider(ABC):
@abstractmethod
def render(self) -> str: ...
class LightButton(Button):
def render(self) -> str:
return "[ OK ] dark text on white"
class LightCheckbox(Checkbox):
def render(self) -> str:
return "[x] dark tick on white"
class LightSlider(Slider):
def render(self) -> str:
return "--o-- grey track on white"
class DarkButton(Button):
def render(self) -> str:
return "[ OK ] white text on black"
class DarkCheckbox(Checkbox):
def render(self) -> str:
return "[x] white tick on black"
class DarkSlider(Slider):
def render(self) -> str:
return "--o-- white track on black"
class ThemeFactory(ABC):
@abstractmethod
def create_button(self) -> Button: ...
@abstractmethod
def create_checkbox(self) -> Checkbox: ...
@abstractmethod
def create_slider(self) -> Slider: ...
class LightTheme(ThemeFactory):
def create_button(self) -> Button:
return LightButton()
def create_checkbox(self) -> Checkbox:
return LightCheckbox()
def create_slider(self) -> Slider:
return LightSlider()
class DarkTheme(ThemeFactory):
def create_button(self) -> Button:
return DarkButton()
def create_checkbox(self) -> Checkbox:
return DarkCheckbox()
def create_slider(self) -> Slider:
return DarkSlider()
def settings_screen(theme: ThemeFactory) -> None:
for widget in [theme.create_button(), theme.create_checkbox(), theme.create_slider()]:
print(widget.render())
settings_screen(LightTheme())
settings_screen(DarkTheme())[ OK ] dark text on white
[x] dark tick on white
--o-- grey track on white
[ OK ] white text on black
[x] white tick on black
--o-- white track on blackThemeFactory is the abstract factory, with create_button, create_checkbox and create_slider. LightTheme and DarkTheme are the concrete factories.
A toggle switch is the expensive change: three new classes, Toggle, LightToggle and DarkToggle, and three edited, since ThemeFactory, LightTheme and DarkTheme each gain create_toggle. A high-contrast theme is the cheap one: four new classes, the factory and its three widgets, and nothing edited.
← → move through sections and cards