Mark Jordan
Posts: 1
Nickname: markjjorda
Registered: Apr, 2006
|
|
Re: Head First Design Patterns
|
Posted: Apr 12, 2006 12:42 PM
|
|
Hi... I read the book... very good read.
However, I am about to blog about the misuse of the decorator pattern, and I use the example in the book as the subject for this topic. I thought I'd post the content here for comment before I post on my blog.
=== Begin Content ===
Is it me, or is the decorator pattern misused? I keep seeing examples of the decorator pattern that make no attempt at providing all public interface methods and properties on the decorator class that are present in the type's public interface. This is wrong, in my opinion.
I recently read the book, "Head First Design Patterns" by Eric Freeman et al. The publisher provides a sample chapter from the book which so happens to be the subject design pattern. You can view the pdf of Chapter 3, "The Decorator Pattern", here: http://www.oreilly.com/catalog/hfdesignpat/chapter/index.html.
In this chapter, they have an example on page 102 whereby they attempt to create a decorator for the FilterInputStream class. They override 2 method interfaces for the "read" method, effectively decorating the subject FilterInputStream that was passed in during construction/instantiation of the decorator.
Here is a reprint of the code:
public class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in) { super(in); } public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char)c)); } public int read(byte[] b, int offset, int len) throws IOException { int result = super.read(b, offset, len); for (int i = offset; i < offset+result; i++) { b = (byte)Character.toLowerCase((char)b); } return result; } }
And now my question… what about all of the other public methods and properties? They also need to be in the decorator class to effectively delegate the reference of them to the FilterInputStream object that we are encapsulating. For instance, where is the following in the decorator class (syntactical errors not important):
public void reset() { super.reset(); }
GoF clearly indicates that "a decorator objects interface must conform to the interface of the component it decorates." Thus, the example in this book is incorrect per GoF specification. There is no way that this decorator object could be seemlessly referenced in place of the object it decorates. Why? Take the lines of code below (again, disregard syntax for the moment):
filterInputStream = new FilterInputStream() filterInputStream.reset(); filterInputStreamDecorator = new FilterInputStreamDecorator(filterInputStream); filterInputStreamDecorator.reset();
The second line would execute fine. But what about the fourth line? Without the code I mentioned above that delegates the reset method on the decorator to the encapsulated object, what gets reset? -- Certainly not the encapsulated object!
Some might be tempted to argue that the patterns are only suggestive, and that variances could be allowed. However, I submit that by providing a decorator without all of the interface, you are merely creating a helper class. To wit, you might as well just create a normal class that does not inherit from the type of the encapsulated object.
Keywords: decorator pattern, Gang of Four, incorrect, wrong
|
|