Design Patterns - Decorator

design-patterns

https://code.tutsplus.com/articles/a-beginners-guide-to-design-patterns--net-12752 - done reading

// Design Patterns - Structural - Decorator:

Decorator pattern allows a user to add new functionality to an existing object 
without altering its structure. This type of design pattern comes under 
structural pattern as this pattern acts as a wrapper to existing class.

This pattern creates a decorator class which wraps the original class and 
provides additional functionality keeping class methods signature intact.

Add responsibilities to objects dynamically. Easy to add behavior at runtime.
The decorator pattern is a structural design pattern which enables us to add 
new or additional behavior to an object during runtime, depending on the 
situation.  The goal is to make it so that the extended functions can be 
applied to one specific instance, and, at the same time, still be able to 
create an original instance that doesn't have the new functions. It also allows 
for combining multiple decorators for one instance, so that you're not stuck 
with one decorator for each instance. This pattern is an alternative to 
subclassing, which refers to creating a class that inherits functionality from 
a parent class. As opposed to subclassing, which adds the behavior at compile 
time, "decorating" allows you to add new behavior during runtime, if the 
situation calls for it.

To implement the decorator pattern, we can follow these steps:

1. Subclass the original "Component" class into a "Decorator" class
2. In the Decorator class, add a Component pointer as a field
3. Pass a Component to the Decorator constructor to initialize the Component 
   pointer
4. In the Decorator class, redirect all "Component" methods to the "Component" 
   pointer, and
5. In the Decorator class, override any Component method(s) whose behavior needs 
   to be modified.

// Step 1: Create an interface.
public interface Shape {
   void draw();
}

// Step 2: Create concrete classes implementing the same interface.
public class Rectangle implements Shape {
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}

public class Circle implements Shape {
   public void draw() {
      System.out.println("Shape: Circle");
   }
}

// Step 3: Create abstract decorator class implementing the Shape interface.
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }

   public void draw(){
      decoratedShape.draw();
   }    
}

// Step 4: Create concrete decorator class extending the ShapeDecorator class.
public class RedShapeDecorator extends ShapeDecorator {
   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);        
   }

   public void draw() {
      decoratedShape.draw();           
      setRedBorder(decoratedShape);
   }

   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

// Step 5: Use the RedShapeDecorator to decorate Shape objects
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());

Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();

System.out.println("\nCircle of red border");
redCircle.draw();

System.out.println("\nRectangle of red border");
redRectangle.draw();

In the above code, we instantiate two instances of the RedShapeDecorator class, 
one instance wraps around the Circle object, and the other instance wraps 
around the Rectangle object.  The draw method of the RedShapeDecorator class 
forward the call to the wrapped object, but add additional functionality either 
before or after the call.

The best place to use the decorator pattern is when you have an entity which 
needs to have new behavior only if the situation requires it. Let's say you 
have an HTML link element, a logout link, that you want to do slightly different 
things to based on the current page. For that, we can use the decorator pattern. 
First, let's establish the different "decorations" we'll need:

1. If we're on the home page and logged in, have this link be wrapped in h2 tags
2. If we're on a different page and logged in, have this link be wrapped in 
   underline tags.
3. If we're logged in, have this link wrapped in strong tags

<?php
class HtmlLinks {
    //some methods which is available to all html links
}

class LogoutLink extends HtmlLinks {
    protected $_html;

    public function __construct() {
        $this->_html = "<a href=\"logout.php\">Logout</a>";
    }

    public function setHtml($html)
    {
        $this->_html = $html;
    }

    public function render()
    {
        echo $this->_html;
    }
}

class LogoutLinkH2Decorator extends HtmlLinks {
    protected $_logout_link;

    public function __construct( $logout_link )
    {
        $this->_logout_link = $logout_link;
        $this->setHtml("<h2>" . $this->_html . "</h2>");
    }

    public function __call( $name, $args )
    {
        $this->_logout_link->$name($args[0]);
    }
}

class LogoutLinkUnderlineDecorator extends HtmlLinks {
    protected $_logout_link;

    public function __construct( $logout_link )
    {
        $this->_logout_link = $logout_link;
        $this->setHtml("<u>" . $this->_html . "</u>");
    }

    public function __call( $name, $args )
    {
        $this->_logout_link->$name($args[0]);
    }
}

class LogoutLinkStrongDecorator extends HtmlLinks {
    protected $_logout_link;

    public function __construct( $logout_link )
    {
        $this->_logout_link = $logout_link;
        $this->setHtml("<strong>" . $this->_html . "</strong>");
    }

    public function __call( $name, $args )
    {
        $this->_logout_link->$name($args[0]);
    }
}

We should then be able to use it like so:

$logout_link = new LogoutLink(); 
if( $is_logged_in ) {
    $logout_link = new LogoutLinkStrongDecorator($logout_link);
}
if( $in_home_page ) {
    $logout_link = new LogoutLinkH2Decorator($logout_link);
} else {
    $logout_link = new LogoutLinkUnderlineDecorator($logout_link);
}
$logout_link->render();

We can see here how we are able to combine multiple decorators if we need them. 
Since all the decorators use the __call magic function, we can still call the 
original function's methods.

In the above code, we have 5 classes:

1. HtmlLinks
2. LogoutLink
3. LogoutLinkH2Decorator
4. LogoutLinkUnderlineDecorator
5. LogoutLinkStrongDecorator

The first two classes (HtmlLinks and LogoutLink) are base classes.  
There is nothing special about them.  The other classes (LogoutLinkH2Decorator, 
LogoutLinkUnderlineDecorator, LogoutLinkStrongDecorator) all have a member 
variable name $_logout_link, and their constructor function all take a object 
of the LogoutLink class.  These classes keep this object in the $_logout_link 
member variable.  These classes use the magic @@__call@@  function to forward 
the invocation to the original object.  

This pattern creates a decorator class which wraps the original class and 
provides additional functionality keeping class methods signature intact.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License