Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator pattern implementations - extends vs implements

I create decorator pattern example:

interface:

public interface Printer {
  void print(String message);
}

implementation:

public class StringPrinter implements Printer {

  public void print(String message) {
    System.out.println(message);
  }
}

and 2 decorators:

change string to upper case:

public class UpCasePrinter implements Printer {

  private Printer printer;

  public UpCasePrinter(Printer printer) {
    this.printer = printer;
  }

  public void print(String message) {
    printer.print(message.toUpperCase());
  }
}

print reverse string:

public class InversePrinter implements Printer {

  private Printer printer;

  public InversePrinter(Printer printer) {
    this.printer = printer;
  }

  public void print(String message) {
    StringBuilder builder = new StringBuilder(message);
    printer.print(builder.reverse().toString());
  }
}

All work fine. But when reading examples on different sites I find different implementations. Each decarator extends from another. And I saw the realization of BufferedInputStream

BufferedInputStream extends FilterInputStream
FilterInputStream extends InputStream
public abstract class InputStream implements Closeable

I can not understand the following:

  1. Is there a difference in how to create a decorator? as for me - the decorator implements the same interface as the original class or as in the examples - the decorator is extends from another decorator, etc. link for extends realization

  2. may be in the example with the BufferedInputStream such a realization only because the abstract class was chosen at the start and not the interface?

EDIT:

enter image description here

in other words, I do not understand what is the use CarDecorator

LuxerCar and SportsCar can implement Car interface and not extends from CarDecorator. What is the benefit?

like image 394
ip696 Avatar asked Mar 06 '23 19:03

ip696


1 Answers

BufferedInputStream is implemented in exactly the same way as your Car example. It decorates an InputStream which, although it's an abstract class, still provides a contract, just as an interface would. An abstract class was chosen in this case because there are methods with default behaviour (read and skip) and, at the time the class was written, interfaces were not able to support this (they can now, but default methods in interfaces were added much later).

Because an abstract class was used for the contract, BufferedInputStream extends FilterInputStream, just as CarDecorator implements Car. Both are just simple holders for a delegate. They contain a single protected field (an InputStream and a Car) and delegate all method calls to the field. The reason for this is because, if you have a large number of methods in your contract, delegating all of the methods in every decorator might result in a lot of code duplication. When your interface only has a single method, as yours does, then it provides very little benefit.

This is certainly not a necessary component of the decorator pattern; it's just a slightly different way of implementing it. Your implementation is still a 100% correct implementation of the decorator pattern.

like image 101
Michael Avatar answered Mar 16 '23 18:03

Michael