31

I feel like I've been using these pattern families quite many times, however, for me it's hard to see the differences as their definitions are quite similar. Basicaly it seems like all of them is about wrapping another object or objects to extend or wrap their behavior with extra stuff.

For a quick example implementing a caching mechanism over a repository pattern seems to be this situation. Here is a quick sample C# code I would probably start with.

public interface IRepository {
  IEnumerable<T> GetItems<T>();
}

public class EntityFrameworkRepository : IRepository {
  ...
}

public class CachedRepository : IRepository {

  private IRepository _repository;
  private ICacheProvider _cache;

  public CachedRepository(IRepository repository, ICacheProvider cache) {
    this._repository = repository;
    this._cache = cache;
  }

  public IEnumerable<T> GetItems<T>() {
    ...
  }
}

Which one of these patterns apply to this situation for example? Could anyone clarify briefly the differences in theory and in practice?

Zoltán Tamási
  • 12,249
  • 8
  • 65
  • 93
  • Possible duplicate of [How do the Proxy, Decorator, Adapter, and Bridge Patterns differ?](http://stackoverflow.com/questions/350404/how-do-the-proxy-decorator-adapter-and-bridge-patterns-differ) – jaco0646 Dec 06 '16 at 14:33
  • Related: http://stackoverflow.com/questions/3489131/difference-between-the-facade-proxy-adapter-and-decorator-design-patterns – jaco0646 Dec 06 '16 at 14:33

2 Answers2

36

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.

ADJenks
  • 2,973
  • 27
  • 38
Kenneth
  • 28,294
  • 6
  • 61
  • 84
  • 1
    Okay, I'm deleting my answer. :) – lexicore Dec 06 '16 at 13:12
  • 1
    The source of my confusion was "wrapper" as a separate pattern, which I've definitely read somewhere if I remember correctly. In the meantime another person confirmed that "wrapper" is rather a coding technique, which allows you to implement for example the decorator pattern. Thank you both for the clarification. – Zoltán Tamási Dec 06 '16 at 13:15
  • Good stuff! I've stolen a bit from @lexicore answer on the adapter for future visitors. – Kenneth Dec 06 '16 at 13:17
  • I've heard wrapper being used when the function is explicitly wrapped, like `wrap(myFunction(args), wrapArgs)`. And decorator when a single line is added on top, like `@wrap(wArgs); myFunction(args)`, with the second being syntactic sugar for the first – Juan Perez Jul 12 '23 at 13:36
14

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);
  }
}

Luke Hanks
  • 179
  • 1
  • 5