What are the differences between Decorator, Wrapper and Adapter patterns?

In theory they are the same, it's the intent that differentiates one pattern from the other:

Decorator:

Allows objects to be composed/add capabilities by wrapping them with a class with the same interface

Adapter:

Allows you to wrap an object without a known interface implementation so it adheres to an interface. The point is to "translate" one interface into another.

Wrapper:

Never heard of this as a design pattern, but I suppose it's just a common name for the above

The example you specify I would categorize as a decorator: The CacheRepository decorates an IRepository to add caching capabilities.


A programmer may write a class A with a focus on holding an object of another class B. Class A would be referred to as a wrapper for class B. Why have class A wrap around class B? To decorate or adapt it. Decorators and adapters are wrappers.


Imagine that class A is written such that it implements the interface of class B by calling the methods of its class B object. It could then be used in place of class B. There's no point in this other than the fact that it gives the programmer the opportunity to add some code before or after the calls to the methods of the class B object. This version of class A would be called a decorator of class B. Decorators leave the interface the same while adding some behavior.

interface ICatInterface {
  public void wakeUp();
}

class Cat implements ICatInterface {
  public void wakeUp() {
    System.out.println("I came. I saw. I napped.");
  }
}

class YogaCat implements ICatInterface {

  private ICatInterface cat;

  public YogaCat(ICatInterface cat) {
    this.cat = cat;
  }

  public void wakeUp() {
    System.out.println("[Stretch]"); // <- This is the decoration.
    cat.wakeUp();
  }
}

See this example of a more complicated way to use this pattern for composing objects of differing behavior during runtime.


Imagine now that class A is written such that it implements some interface C, but is implemented mostly via calls to the methods of its class B object. This is a way to translate the methods available in class B to interface C. This version of class A would be called an adapter of class B. It's like when you want to charge your phone. There are adapters that go from wall or car power source to USB port. Adapters change the interface to some other interface, but don't necessarily add any behaviors.

interface TakeDirectionsInterface {
  public void turnLeft();
  public void turnRight();
  public void go();
  public void stop();
}

class Driver {
  public enum TurnDirection
  { 
    CLOCKWISE, COUNTERCLOCKWISE;
  }

  public enum FootPedal
  { 
    ACCELERATOR, BRAKE, CLUTCH;
  }

  public void turnSteeringWheel(TurnDirection direction) {
    System.out.println("Turning the steering wheel " + direction.toString() + ".");
  }

  public void pressPedal(FootPedal pedal) {
    System.out.println("Pressing the " + pedal.toString() + "pedal.");
  }
}

class DriverAdapter implements TakeDirectionsInterface {

  private Driver driver;

  public DriverAdapter(Driver driver) {
    this.driver = driver;
  }

  public void turnLeft(){
    driver.turnSteeringWheel(Driver.TurnDirection.COUNTERCLOCKWISE);
  }

  public void turnRight(){
    driver.turnSteeringWheel(Driver.TurnDirection.CLOCKWISE);
  }

  public void go(){
    driver.pressPedal(Driver.FootPedal.ACCELERATOR);
  }

  public void stop(){
    driver.pressPedal(Driver.FootPedal.BRAKE);
  }
}