---
# System prepended metadata

title: DECORATOR

---

DECORATOR
===
# Decorator
- is a structural design pattern
- that lets you attach new behaviors to objects
- by placing these objects inside special wrapper objects
- that contain the behaviors.

# Problem


```python
# Imagine that you’re working on
# - a notification library
# - which lets other programs
# - notify their users
# - about important events.
#
# The initial version of the library
# - was based on the Notifier class
# - that had only a few fields
# - a constructor and a single send method
class Notifier(object):
    def __init__(self):
        pass

    def send(self, message):
        # a single send method
        # The method could
        # - accept a message argument
        # - from a client
        # - and send the message
        # - to a list of emails
        # - that were passed to the notifier via its constructor
        print("App::", message)

```

```python
class Application(object):
    # A third-party app
    # - which acted
    # - as a client was supposed
    # - to create and configure the notifier object once,
    # - and then use it each time something important happened.
    def __init__(self):
        self.notifier = Notifier()

    def set_notifier(self, notifier: Notifier):
        self.notifier = notifier

    def do_something(self):
        self.notifier.send("Alert!")
```

At some point,
- you realize 
- that users of the library
- expect more than just email notifications.

```python
# Many of them
# - would like to receive an SMS about critical issues.
# Others
# - would like to be notified on Facebook and,
# - of course, the corporate users would love to get Slack notifications.
# How hard can that be?
# - You extended the Notifier class
# - and put the additional notification methods into new subclasses.

class SMSNotifier(Notifier):
    def send(self, message):
        print("sms::", message)


class FacebookNotifier(Notifier):
    def send(self, message):
        print("Facebook::", message)


class SlackNotifier(Notifier):
    def send(self, message):
        print("Slack::", message)

```

Now the client
- was supposed to instantiate the desired notification class
- and use it for all further notifications.


```python
# But then someone reasonably asked you,
# - “Why can’t you use several notification types at once?
# - If your house is on fire, you’d probably 
#   want to be informed through # every channel.”
# You tried
# - to address that problem by creating special subclasses
# - which combined several notification methods within one
#   class.
class SMSFaceBookNotifier(Notifier):
    def send(self, message):
        print("SMS&FaceBook::", message)


class SMSSlackNotifier(Notifier):
    def send(self, message):
        print("SMS&Slack::", message)


class SMSFaceBookSlackNotifier(Notifier):
    def send(self, message):
        print("SMS&FaceBock&Slack::", message)


class FacebookSlackNotifier(Notifier):
    def send(self, message):
        print("FaceBock&Slack::", message)
```



```python
# However, it
# - quickly became apparent that this approach
# - would bloat the code immensely,
# - not only the library code
# - but the client code as well.
#
# You have to find some other way
# - to structure notifications classes
# - so that their number
# - won’t accidentally break some Guinness record.
def main():
    message = "message"

    is_facebook_notifier = True
    is_app_notifier = True
    if_is_slack_notifier = True

    if is_facebook_notifier:
        notifier = FacebookNotifier()
        notifier.send(message)

    if is_app_notifier:
        notifier = Notifier()
        notifier.send(message)

    if if_is_slack_notifier:
        notifier = SlackNotifier()
        notifier.send(message)


if __name__ == "__main__":
    main()

```
# Solution
<!--
Extending a class
- is the first thing
- that comes to mind
- when you need to alter an object’s behavior.

However, inheritance 
- has several serious caveats
- that you need to be aware of.


Inheritance is static. You
- can’t alter the behavior
- of an existing object at runtime.

You
- can only replace the whole object
- with another one that’s created
- from a different subclass.

Subclasses can have just one parent class.
- In most languages, inheritance
- doesn’t let a class inherit behaviors
- of multiple classes at the same time.

One of the ways
- to overcome these caveats is 
- by using Aggregation or Composition instead of Inheritance.
- Both of the alternatives work almost the same way:
- one object has a reference to another
- and delegates it some work,
- whereas with inheritance,
- the object itself is able to do that work,
- inheriting the behavior from its superclass. -->


<!--“Wrapper” is the alternative
- nickname for the Decorator pattern
- that clearly expresses the main idea of the pattern.

A wrapper
- is an object
- that can be linked
- with some target object.


The wrapper
- contains the same set of methods as the target
- and delegates to it all requests it receives.

However, the wrapper
- may alter the result
- by doing something either before
- or after it passes the request to the target. -->


<!--
When does a simple wrapper
- become the real decorator?

As I mentioned, the wrapper
- implements the same interface as the wrapped object.
- That’s why from the client’s perspective these objects are identical.

Make the wrapper’s
- reference field accept any object
- that follows that interface.

This will let you cover an object in multiple wrappers,
- adding the combined behavior of all the wrappers to it.-->

```python
class Notifier(object):
    def send(self, message):
        print("App::", message)


class BaseDecorator(object):
    # In our notifications example,
    # - let’s leave the simple email notification behavior
    # - inside the base Notifier class,
    # - but turn all other notification methods into decorators.
    def __init__(self, notifier):
        self.wrappee = notifier

    def send(self, message):
        self.wrappee.send(message)

```
```python
class SMSDecorator(BaseDecorator):
    def send(self, message):
        self.wrappee.send(message)
        print("sms::", message)


class FacebookDecorator(BaseDecorator):
    def send(self, message):
        self.wrappee.send(message)
        print("Facebook::", message)


class SlackDecorator(BaseDecorator):
    def send(self, message):
        self.wrappee.send(message)
        print("Slack::", message)

```

```python
def main():
    message = "message"

    is_facebook_notifier = True
    is_sms_notifier = True
    if_is_slack_notifier = True

    notifier = Notifier()
    if is_facebook_notifier:
        notifier = FacebookDecorator(notifier)

    if is_sms_notifier:
        notifier = SMSDecorator(notifier)

    if if_is_slack_notifier:
        notifier = SlackDecorator(notifier)
    # Since all decorators implement the same interface
    # - as the base notifier,
    # - the rest of the client code 
    # - won’t care whether it
    # - works with the “pure” notifier object
    # - or the decorated one.
    #
    # The resulting objects
    # - will be structured as a stack.
    #
    # The last decorator
    # - in the stack
    # - would be the object
    # - that the client actually works with.
    #
    # We
    # - could apply the same approach
    # - to other behaviors such as
    # - formatting messages
    # - or composing the recipient list.
    #
    # The client
    # - can decorate the object
    # - with any custom decorators,
    # - as long as they
    # - follow the same interface as the others.
    # notifier.send(message)    
    notifier.send()


if __name__ == "__main__":
    main()
```


# Applicability

Use the Decorator pattern
- when you need to be able
- to assign extra behaviors
- to objects at runtime
- without breaking the code that uses these objects.

<!-- The Decorator
- lets you structure your business logic into layers,
- create a decorator
- for each layer
- and compose objects
- with various combinations
- of this logic at runtime.

The client code
- can treat all these objects in the same way,
- since they all follow a common interface. -->


---
Use the pattern
- when it’s awkward
- or not possible to extend an object’s behavior
- using inheritance.

<!--
Many programming languages
- have the final keyword
- that can be used
- to prevent further extension
- of a class.

For a final class,
- the only way
- to reuse the existing behavior
- would be to wrap the class with your own wrapper,
- using the Decorator pattern.-->

