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:
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
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:
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With