Fork me on GitHub
Tutorial Home

Decorator

Story

Attach additional responsibilities to an object dynamically.

The spoilers that are added to a car are examples of the Decorator. The spoilers do not change the car itself, but adds additional functionality which is to ‘spoil’ unfavorable air movement across a body of a vehicle in motion, usually described as turbulence or drag.

Image

alt text

steve lyon from los angeles, ca, usa, 2013 Porsche 911 Carrera S (8233337583), CC BY-SA 2.0

UML

Implementation

Component.java

package com.hundredwordsgof.decorator;

/**
 * 
 * Component, defines interface for new features which will be added dynamicaly
 *
 */
public interface Component {

  void operation();
}

ConcreteComponent.java

package com.hundredwordsgof.decorator;

/**
 * 
 * ConcreteComponent, define object where new features can be added
 *
 */
public class ConcreteComponent implements Component {

  public void operation() {
  }
}

Decorator.java

package com.hundredwordsgof.decorator;

/**
 * 
 * Decorator, keep reference to Component object
 *
 */
abstract class Decorator implements Component {

  protected Component component;

  public abstract void operation();

  public void setComponent(Component component) {
    this.component = component;
  }
}

ConcreteDecoratorA.java

package com.hundredwordsgof.decorator;

/**
 * 
 * ConcreteDecoratorA, add features to component
 *
 */
public class ConcreteDecoratorA extends Decorator {

  private boolean state;

  public void operation() {
    state = true;
    this.component.operation();
  }

  public boolean isState() {
    return state;
  }
}

ConcreteDecoratorB.java

package com.hundredwordsgof.decorator;

/**
 * 
 * ConcreteDecoratorB, add features to component
 *
 */
public class ConcreteDecoratorB extends Decorator {

  private boolean behaviorMethodInvoked = false;

  public void operation() {
    this.component.operation();
    addedBehavior();
  }

  private void addedBehavior() {
    behaviorMethodInvoked = true;
  }

  protected boolean isBehaviorMethodInvoked() {
    return behaviorMethodInvoked;
  }
}

Usage

DecoratorTest.java

package com.hundredwordsgof.decorator;

import static org.junit.Assert.assertEquals;
import org.junit.Test;

/**
 * Test Decorator pattern.
 */
public class DecoratorTest {

  @Test
  public void testDecorator() {

    Component component = new ConcreteComponent();

    Decorator decoratorA = new ConcreteDecoratorA();
    decoratorA.setComponent(component);
    decoratorA.operation();

    assertEquals(true, ((ConcreteDecoratorA) decoratorA).isState());

    Decorator decoratorB = new ConcreteDecoratorB();
    decoratorB.setComponent(component);

    assertEquals(false,
        ((ConcreteDecoratorB) decoratorB).isBehaviorMethodInvoked());

    decoratorB.operation();

    assertEquals(true,
        ((ConcreteDecoratorB) decoratorB).isBehaviorMethodInvoked());
  }
}