MyTetra Share
Делитесь знаниями!
Декоратор
12.04.2018
12:19
Автор: br0ke
Текстовые метки: oop, design pattern, pattern, structural, decorator
Раздел: Информационные технологии - Паттерны проектирования (ООП) - Структурные

Декоратор -- структурный паттерн, который позволяет динамически добавлять к объектам новую функциональность, оборачивая их в полезные "обертки". При этом для подключения дополнительной функциональности используется не сложная иерархия подклассов, что является классическим (и тупым) решением данной задачи, а отдельная иерархия декораторов.


Каждый из видов дополнительной функциональности, которая может быть добавлена к объекту, помещается в отдельный класс. Эти классы сами по себе небольшие, поэтому в них легко разобраться.


В паттерн "Декоратор" входят оборачиваемый объект и сама иерархия декораторов. Каждый из декораторов реализует какое-то одно функциональное свойство. Это позволяет соблюдать один из SOLID принципов -- принцип единственной ответственности. Так мы можем подключить к классу только ту функциональность, которая необходима ему в данный момент. Для подключения нескольких функциональных свойств можно последовательно использовать несколько декораторов.


Структура декораторов


Для создания паттерна "Декоратор" необходимы следующие классы:

  • Абстрактный объект (Component)
  • Оборачиваемый объект (на UML-диаграмме ConcreteComponent)
  • Абстрактный декоратор (Decorator)
  • Конкретный декоратор (ConcreteDecorator)

Как видно из диаграммы, все декораторы по сути являются объектами, подобными самому компоненту. Из этого следует, что они реализуют одинаковый интерфейс. Согласно принципу подстановки Барбары Лисков у пользователя должна быть возможность корректного использования объекта-декоратора (то есть объекта, обернутого в декоратор), не зная об этом.

Тут находится одно из слабых мест паттерна. Интерфейс объекта и интерфейс модифицированного объекта одинаковы. Это не всегда удобно, иногда для модифицированного объекта требуется отдельный интерфейс.

Использование паттерна Декоратор

При использовании паттерна декорируемый объект оборачивается в декоратор. Таким образом получается вложенная структура из декораторов. Отменить действие декоратора можно, если достать базовый объект из декоратора. Это можно сделать, обратившись к decorated_object.base. Аналогичным образом можно отменить эффект декоратора из середины иерархии. Для этого изменим базовый объект у внешнего декоратора на базовый объект декоратора, который необходимо удалить. Принцип похож на удаление элемента из середины односвязного списка.

Пример использования Декоратора

from abc import ABC, abstractmethod


class Creature(ABC):

@abstractmethod

def feed(self):

pass

@abstractmethod

def move(self):

pass

@abstractmethod

def make_noise(self):

pass

class Animal(Creature):

def feed(self):

print("I eat grass")

def move(self):

print("I walk forward")

def make_noise(self):

print("WOOO!")

class AbstractDecorator(Creature):

def __init__(self, obj):

self.obj = obj

def feed(self):

self.obj.feed()

def move(self):

self.obj.move()

def make_noise(self):

self.obj.make_noise()

class Swimming(AbstractDecorator):

def move(self):

print("I swim")

def make_noise(self):

print("...")

class Flying(AbstractDecorator):

def move(self):

print("I fly")

def make_noise(self):

print("QUAAA!")

class Predator(AbstractDecorator):

def feed(self):

print("I eat other animals")

class Fast(AbstractDecorator):

def move(self):

self.obj.move()

print("Fast!")


animal = Animal()

animal.feed() # I eat grass

animal.move() # I walk forward

animal.make_noise() # WOOO!

print()


animal = Swimming(animal)

animal.feed() # I eat grass

animal.move() # I swim

animal.make_noise() # ...

print()


animal = Predator(animal)

animal.feed() # I eat other animals

animal.move() # I swim

animal.make_noise() # ...

print()


animal = Fast(animal)

animal.feed() # I eat other animals

animal.move() # I swim Fast!

animal.make_noise() # ...

print()



animal = Fast(animal)

animal.feed() # I eat other animals

animal.move() # I swim Fast! Fast!

animal.make_noise() # ...

print()



Прикрепленные файлы:
Так же в этом разделе:
 
MyTetra Share v.0.52
Яндекс индекс цитирования