Эти шаблоны в основном посвящены компоновке объектов (object composition). То есть тому, как сущности могут друг друга использовать. Ещё одно объяснение: структурные шаблоны помогают ответить на вопрос «Как построить программный компонент?»
Адаптер
Аналогия
Допустим, у вас на карте памяти есть какие-то картинки. Их нужно перенести на компьютер. Нужен адаптер, совместимый с входным портом компьютера, в который можно вставить карту памяти. В данном примере адаптер — это картридер. Ещё один пример: переходник, позволяющий использовать американский блок питания с российской розеткой. Третий пример: переводчик — это адаптер, соединяющий двух людей, говорящих на разных языках.
Вкратце
Шаблон «Адаптер» позволяет помещать несовместимый объект в обёртку, чтобы он оказался совместимым с другим классом.
Пример
Представим себе охотника на львов.
Создадим интерфейс Lion
, который реализует все типы львов.
from abc import ABC, abstractmethod
class Lion(ABC):
@abstractmethod
def roar(self):
pass
class AfricanLion(Lion):
def roar(self):
pass
class AsianLion(Lion):
def roar(self):
pass
Охотник должен охотиться на все реализации интерфейса Lion
.
class Hunter:
def hunt(lion: Lion):
pass
Добавим теперь дикую собаку WildDog
, на которую охотник тоже может охотиться. Но у нас не получится сделать это напрямую, потому что у собаки другой интерфейс. Чтобы она стала совместима с охотником, нужно создать подходящий адаптер.
class WildDog:
def bark(self):
pass
# Адаптер вокруг собаки сделает её совместимой с охотником
class WildDogAdapter(Lion):
def __init__(self, dog: WildDog):
self.dog = dog
def road(self):
self.dog.bark()
Теперь WildDog
может вступить в игру действие благодаря WildDogAdapter
.
wild_dog = WildDog()
wild_dog_adapter = WildDogAdapter(wild_dog)
hunter = Hunter()
hunter.hunt(wild_dog_adapter)
Мост
Аналогия
Допустим, у вас есть сайт с несколькими страницами. Вы хотите позволить пользователям менять темы оформления страниц. Как бы вы поступили? Создали множественные копии каждой страницы для каждой темы или просто сделали отдельные темы и подгружали их в соответствии с настройками пользователей? Шаблон «Мост» позволяет реализовать второй подход.
Вкратце
Шаблон «Мост» — это предпочтение компоновки наследованию. Подробности реализации передаются из одной иерархии другому объекту с отдельной иерархией.
Пример
Реализуем вышеописанный пример с веб-страницами. Сделаем иерархию WebPage
:
from abc import ABC, abstractmethod
class WebPage(ABC):
def __init__(self, theme: Theme):
self.theme = theme
@abstractmethod
def get_content(self):
pass
class About(WebPage):
def get_content(self):
return "About page in " + self.theme.get_color()
class Careers(WebPage):
def get_content(self):
return "Careers page in " + self.theme.get_color()
Отделим иерархию тем:
from abc import ABC, abstractmethod
class Theme(ABC):
@abstractmethod
def get_color(self):
pass
class DarkTheme(Theme):
def get_color(self):
return "Dark Black"
class LightTheme(Theme):
def get_color(self):
return "Off white"
class AquaTheme(Theme):
def get_color(self):
return "Light blue"
Обе иерархии:
dark_theme = DarkTheme()
about = About(dark_theme)
careers = Careers(dark_theme)
about.get_content() # "About page in Dark Black"
careers.get_content() # "Careers page in Dark Black"