В разработке часто возникает необходимость динамического добавления функциональности к объектам без прямого изменения их структуры. Например, необходимо добавить дополнительный слой безопасности, логирование или модерацию контента. Модификация существующего кода для добавления таких функций может привести к непредвиденным последствиям, включая внесение ошибок в работающий код и нарушение принципов SOLID.
В таком случае применяется паттерн проектирования под названием «Декоратор». Он обертывает объект, добавляет новую функциональность и сохраняет исходный интерфейс. Так объект, который работает с исходным классом, может продолжать работать без изменений даже после применения декоратора.
В этом уроке мы разберем, как реализовать паттерн «Декоратор» и поговорим о преимуществах и недостатках использования декораторов.
Как реализовать паттерн «Декоратор»
Декоратор — это паттерн, который позволяет динамически добавлять новые функции к объекту без изменения его структуры. Это достигается за счет создания функции, которая оборачивает исходный объект и добавляет новое поведение.
В Python паттерн «Декоратор» можно легко реализовать с помощью встроенной функциональности декораторов. Но сначала мы рассмотрим его реализацию в более общем ООП стиле для лучшего понимания. Разберем применение этого паттерна по шагам.
Представим, что у нас есть система для управления блогом. Нам нужно добавить функциональность для модерации комментариев. Некоторые комментарии могут содержать нежелательные слова, которые мы хотим фильтровать.
- Создадим базовый класс
Comment
, который будет содержать текст комментария и методdisplay
, отображающий этот текст:
class Comment:
def __init__(self, text):
self.text = text
def display(self):
return self.text
Класс Comment
является базовым и представляет собой комментарий с текстом и методом display
для его отображения. Этот класс служит основой для нашего декоратора.
Теперь, чтобы добавить функциональность фильтрации нежелательных слов, мы могли бы изменить класс Comment
. Но это нарушило бы принцип открытости-закрытости SOLID. Вместо этого мы можем использовать паттерн «Декоратор».
- Создадим декоратор
ProfanityFilterDecorator
, который будет фильтровать нежелательные слова:
class ProfanityFilterDecorator:
def __init__(self, comment):
self.comment = comment
self.profanities = {"badword1", "badword2"}
def display(self):
words = self.comment.display().split()
result_words = [
word if word not in self.profanities else "***" for word in words
]
return " ".join(result_words)
В этом примере класс ProfanityFilterDecorator
оборачивает объект Comment
и переопределяет метод display
так, чтобы фильтровать определенные нежелательные слова в тексте комментария. Исходный объект Comment
остается неизменным, а декоратор добавляет новое поведение — фильтрацию нежелательных слов.
Это показывает, как декоратор может изменять поведение декорируемого объекта без изменения его структуры.
- Создадим комментарий и применим к нему декоратор для фильтрации нежелательных слов:
comment = Comment("This is a comment with a badword1")
print(comment.display()) # => "This is a comment with a badword1"
comment = ProfanityFilterDecorator(comment)
print(comment.display()) # => "This is a comment with a ***"
Здесь мы видим пример использования полиморфизма: объект ProfanityFilterDecorator
ведет себя как объект Comment
, но добавляет новое поведение — фильтрацию нежелательных слов.
Еще с помощью паттерна «Декоратор» можно создавать новые классы декораторов без изменения существующих классов, чтобы динамически добавлять новую функциональность. Например, можно создать декоратор, который добавляет автоматический перевод комментариев на другой язык.
Выводы
Декораторы могут быть очень мощным инструментом. Но использование большого количества или сложных декораторов может сделать код трудным для понимания и отладки. Они также могут скрывать поведение, которое может быть неочевидным при чтении кода. Поэтому всегда стоит оставлять комментарии, которые объясняют, что делает декоратор.
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.