PERSONAL BLOG
Category: Programming

Шаблоны проектирования. Часть 2. Структурные

Feb. 11, 2025

Эти шаблоны в основном посвящены компоновке объектов (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)

 

Мост

Аналогия

Допустим, у вас есть сайт с несколькими страницами. Вы хотите позволить пользователям менять темы оформления страниц. Как бы вы поступили? Создали множественные копии каждой страницы для каждой темы или просто сделали отдельные темы и подгружали их в соответствии с настройками пользователей? Шаблон «Мост» позволяет реализовать второй подход.

 

image

 

 

Вкратце

Шаблон «Мост» — это предпочтение компоновки наследованию. Подробности реализации передаются из одной иерархии другому объекту с отдельной иерархией.

 

Пример

Реализуем вышеописанный пример с веб-страницами. Сделаем иерархию 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"