9.3. Decorator

9.3.1. Rationale

  • EN: Decorator

  • PL: Dekorator

  • Type: object

9.3.2. Use Cases

  • Add additional behavior to an object

9.3.3. Problem

  • What if we want compression and encryption?

  • What if something else will be added?

class CloudStream:
    def write(self, data: str) -> None:
        print(f'Storing: "{data}"')


class EncryptedCloudStream(CloudStream):
    def write(self, data: str) -> None:
        encrypted: str = self.__encrypt(data)
        super().write(encrypted)

    def __encrypt(self, data: str) -> str:
        return '3817f443b81e986d8e2771c6bf5e744e7ec0e844'


class CompressedCloudStream(CloudStream):
    def write(self, data: str) -> None:
        compressed = self.__compress(data)
        super().write(compressed)

    def __compress(self, data: str) -> str:
        return data[0:10]


if __name__ == '__main__':
    cloud_steam = CloudStream()
    cloud_steam.write('Data')
    # Storing: "Data"

    cloud_steam = EncryptedCloudStream()
    cloud_steam.write('Data')
    # Storing: "3817f443b81e986d8e2771c6bf5e744e7ec0e844"

9.3.4. Design

../../_images/designpatterns-decorator-gof.png

9.3.5. Implementation

../../_images/designpatterns-decorator-usecase.png
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass


class Stream(metaclass=ABCMeta):
    @abstractmethod
    def write(self, data: str) -> None:
        pass


class CloudStream(Stream):
    def write(self, data: str) -> None:
        print(f'Storing: "{data}"')


@dataclass
class EncryptedCloudStream(Stream):
    __stream: Stream

    def write(self, data: str) -> None:
        encrypted: str = self.__encrypt(data)
        self.__stream.write(encrypted)

    def __encrypt(self, data: str) -> str:
        return '3817f443b81e986d8e2771c6bf5e744e7ec0e844'


@dataclass
class CompressedCloudStream(Stream):
    __stream: Stream

    def write(self, data: str) -> None:
        compressed: str = self.__compress(data)
        self.__stream.write(compressed)

    def __compress(self, data: str) -> str:
        return data[0:10]


if __name__ == '__main__':
    credit_card_number = '1234-1234-1234-1234'

    cloud_steam = CloudStream()
    cloud_steam.write(credit_card_number)
    # Storing: "Data"

    cloud_steam = EncryptedCloudStream(CloudStream())
    cloud_steam.write(credit_card_number)
    # Storing: "3817f443b81e986d8e2771c6bf5e744e7ec0e844"

    cloud_steam = EncryptedCloudStream(CompressedCloudStream(CloudStream()))
    cloud_steam.write(credit_card_number)
    # Storing: "3817f443b8"

9.3.6. Assignments