Ответ
Структурные паттерны проектирования помогают организовать классы и объекты в более крупные структуры, сохраняя гибкость, эффективность и упрощая взаимодействие между компонентами. Они описывают, как объекты и классы могут быть скомпонованы для формирования больших структур.
Основные структурные паттерны:
-
Адаптер (Adapter)
- Что делает: Преобразует интерфейс одного класса в другой интерфейс, ожидаемый клиентом, позволяя классам с несовместимыми интерфейсами работать вместе.
- Когда использовать: Когда нужно интегрировать существующий класс, который имеет неподходящий интерфейс, в новую систему.
- Пример:
# Несовместимый класс class OldSystem: def old_request(self): return "Data from Old System"
Ожидаемый интерфейс
class NewSystemTarget: def request(self): pass
Адаптер
class Adapter(NewSystemTarget): def init(self, old_system_instance): self._old_system = old_system_instance
def request(self): return f"Adapter: {self._old_system.old_request()}"Использование
old_obj = OldSystem() adapter = Adapter(old_obj) print(adapter.request()) # Adapter: Data from Old System
-
Декоратор (Decorator)
- Что делает: Динамически добавляет объекту новую функциональность, оборачивая его в объект-декоратор. Это гибкая альтернатива наследованию для расширения функционала.
- Когда использовать: Когда нужно добавить или удалить обязанности объекта во время выполнения, не изменяя его структуру.
- Пример:
class Coffee: def get_cost(self): return 5 def get_ingredients(self): return "Coffee"
class MilkDecorator: def init(self, coffee): self._coffee = coffee def get_cost(self): return self._coffee.get_cost() + 2 def get_ingredients(self): return self._coffee.get_ingredients() + ", Milk"
my_coffee = Coffee() my_coffee = MilkDecorator(my_coffee) print(f"Cost: {my_coffee.get_cost()}, Ingredients: {my_coffee.get_ingredients()}")
Cost: 7, Ingredients: Coffee, Milk
-
Фасад (Facade)
- Что делает: Предоставляет унифицированный (упрощенный) интерфейс к сложной подсистеме, скрывая ее сложность.
- Когда использовать: Когда система состоит из множества взаимосвязанных классов, и нужно предоставить простой способ взаимодействия с ней.
-
Компоновщик (Composite)
- Что делает: Позволяет группировать объекты в древовидные структуры и работать с ними как с отдельными объектами. Клиент может единообразно обращаться как к отдельным объектам, так и к их группам.
- Когда использовать: Когда нужно представить иерархию объектов "часть-целое" и позволить клиентам игнорировать разницу между отдельными объектами и их композициями.
-
Заместитель (Proxy)
- Что делает: Предоставляет суррогат или заполнитель для другого объекта, контролируя доступ к нему. Это позволяет добавить дополнительную логику (например, ленивую инициализацию, кэширование, контроль доступа) перед доступом к реальному объекту.
- Когда использовать: Когда нужен более контролируемый или отложенный доступ к объекту.
-
Мост (Bridge)
- Что делает: Разделяет абстракцию и реализацию, позволяя им изменяться независимо друг от друга. Это достигается путем вынесения реализации в отдельную иерархию.
- Когда использовать: Когда нужно избежать постоянной привязки абстракции к ее реализации или когда и абстракция, и реализация должны расширяться независимо.
-
Приспособленец (Flyweight)
- Что делает: Экономит память, разделяя общее состояние между множеством объектов. Используется, когда большое количество мелких объектов имеет много общего состояния.
- Когда использовать: Когда приложение должно поддерживать большое количество объектов, и их создание или хранение становится слишком затратным по памяти.
Ответ 18+ 🔞
Давай я тебе про структурные паттерны расскажу, как есть, без этих твоих заумных книжек. Это ж просто способ собрать свой код так, чтобы он не развалился, как карточный домик, когда ты на него чихнёшь.
Вот смотри, представь, что твой код — это такая мартышлюшка, которая пытается из конструктора собрать танк. А паттерны — это, блядь, инструкция, как эти шестерёнки между собой скрепить, чтобы не получилась хуйня, которая только в стену умеет ебашиться.
1. Адаптер (Adapter)
Это когда у тебя есть старый, видавший виды утюг с советской вилкой, а тебе надо воткнуть его в европейскую розетку. Ты что делаешь? Берёшь переходничок, сука! Вот этот переходничок — он и есть адаптер. В коде так же: есть какой-то легаси-класс, который орет «Мууу!» как Герасим, а новая система ждёт от него человеческой речи. Адаптер берёт этого немого Герасима, оборачивает и говорит: «Всё, брат, теперь ты умеешь request() делать».
# Это наш Герасим, негостеприимный
class OldSystem:
def old_request(self):
return "Data from Old System"
# А это новая тёлочка-система, которая хочет только по-модному
class NewSystemTarget:
def request(self):
pass
# Сам адаптер-переходник. Хитрая жопа.
class Adapter(NewSystemTarget):
def __init__(self, old_system_instance):
self._old_system = old_system_instance # Сажаем Герасима внутрь
def request(self):
return f"Adapter: {self._old_system.old_request()}" # И за него говорим
# Использование
old_obj = OldSystem()
adapter = Adapter(old_obj)
print(adapter.request()) # Adapter: Data from Old System
Видишь? Герасим как мычал, так и мычит, но через адаптер он уже почти интеллигент.
2. Декоратор (Decorator) О, это любимое! Это как ты приходишь в кофейню: «Дайте мне кофе». «С молоком?» — «Да». «С сиропом?» — «А почему нет?». «С пенкой?» — «Да ебать, давайте уже всё!». Каждый раз тебе не новый кофе делают, а нахуеверчивают поверх старого новые плюшки. В коде — абсолютно так же. Берёшь базовый объект и по цепочке оборачиваешь его в обёртки, которые что-то добавляют.
class Coffee:
def get_cost(self): return 5
def get_ingredients(self): return "Coffee"
class MilkDecorator:
def __init__(self, coffee):
self._coffee = coffee # Заворачиваем кофе в молоко
def get_cost(self): return self._coffee.get_cost() + 2
def get_ingredients(self): return self._coffee.get_ingredients() + ", Milk"
my_coffee = Coffee()
my_coffee = MilkDecorator(my_coffee) # Оборачиваем!
print(f"Cost: {my_coffee.get_cost()}, Ingredients: {my_coffee.get_ingredients()}")
# Cost: 7, Ingredients: Coffee, Milk
И так можно обернуть хоть в десять декораторов, главное — вовремя остановиться, а то получится «Кофе с молоком, сиропом, пенкой, перцем, дошираком и чувством вины».
3. Фасад (Facade) Представь, что ты хочешь завести машину. Тебе похуй, что там: бензонасос, стартер, компьютер, свечи, поршни делают вот эту самую хуйню. Ты просто ключ поворачиваешь (или кнопку жмёшь). Эта кнопка — и есть фасад над пиздецки сложной системой двигателя. В коде фасад — это такой простой класс-привратник, который скрывает за своей спиной овердохуищу других классов, а тебе выдаёт одну-две удобные методы.
4. Компоновщик (Composite) Это паттерн для тех, у кого в голове древо, а не граф. Позволяет работать с одной штукой и с кучей этих штук — абсолютно одинаково. Ну, типа, ты можешь сказать «нарисуй» и одному кружку, и целой папке, в которой лежат кружки, квадратики и ещё три папки. Все они — «графические объекты». Удобно, когда нужно делать одно и то же действие на целую кучу всего разом. Без него пришлось бы городить адские проверки «а это у меня один элемент или мапа?».
5. Заместитель (Proxy) Заместитель — это как твой друг, который говорит: «Отдай мне посылку за тебя получу». А сам её получает, проверяет, не бомба ли, распаковывает, выкидывает счёт за ЖКХ и приносит тебе только конфетки. Контролирует доступ, короче. Ленивая загрузка? Это он. Кэширование? Тоже он. Защита доступа? Опять он, хитрая жопа.
6. Мост (Bridge) Самый, блядь, философский паттерн. Ну, смотри: есть «телевизор», а есть «пульт». Телевизор — это реализация (можно включить, громкость сделать). Пульт — это абстракция (кнопка «вкл», кнопка «громче»). Мост говорит: давайте мы их нахуй разделим, чтобы пульт от «Самсунга» мог работать и с «Сони», и с «Филипсом». И чтобы новый пульт с голосовым управлением можно было сделать, не переписывая все телевизоры в мире. Независимое развитие, епта!
7. Приспособленец (Flyweight) Это для жадных до памяти. Допустим, ты пишешь игру, и там 10 000 деревьев. Каждое дерево — объект, в нём текстура коры, листьев, модель, координаты. Текстура и модель у всех деревьев одинаковая, а координаты — разные. Так зачем 10 000 раз хранить одну и ту же текстуру? Приспособленец говорит: давайте общие данные (текстуру) вынесем в один объект-приспособленец, а в каждом дереве будем хранить только уникальные данные (координаты) и ссылку на этого приспособленца. Экономия — пиздец! Как в том анекдоте: «А халат один на всех, вот номерок».
Вот и все, блядь, структурные паттерны. Не боги горшки обжигают, а программисты, которые вовремя поняли, что если не структурировать этот хаос, то потом придётся всё ебашить с нуля, а это, простите, чих-пых тебя в сраку, никому не нужно.