I've read the decorator design pattern from Wikipedia, and code example from this site.
I see the point that traditional inheritance follows an 'is-a' pattern whereas decorator follows a 'has-a' pattern. And the calling convention of decorator looks like a 'skin' over 'skin' .. over 'core'. e.g.
I* anXYZ = new Z( new Y( new X( new A ) ) );
as demonstrated in above code example link.
However there are still a couple of questions that I do not understand:
what does wiki mean by 'The decorator pattern can be used to extend (decorate) the functionality of a certain object at run-time'? the 'new ...(new... (new...))' is a run-time call and is good but a 'AwithXYZ anXYZ;' is a inheritance at compile time and is bad?
from the code example link I can see that the number of class definition is almost the same in both implementations. I recall in some other design pattern books like 'Head first design patterns'. They use starbuzz coffee as example and say traditional inheritance will cause a 'class explosion' because for each combination of coffee, you would come up with a class for it.
But isn't it the same for decorator in this case? If a decorator class can take ANY abstract class and decorate it, then I guess it does prevent explosion, but from the code example, you have exact # of class definitions, no less...
Would anyone explain?
With decorators, responsibilities can be added and removed at run-time simply by attaching and detaching them. In contrast, inheritance requires creating a new class for each additional responsibility (e.g., BorderedScrollableTextView, BorderedTextView).
We use inheritance or composition to extend the behavior of an object but this is done at compile time and its applicable to all the instances of the class.
The union design pattern is a structural pattern that depicts the inheritance relationship between a superclass and its subclasses. The superclass is an abstract representation of the union of all the subclasses. Due to this polymorphism, the subclasses can thus be used wherever the superclass is required.
Disadvantages. High degree of flexibility. High complexity of software (especially decorator interface) Expansion of function of classes without inheritance.
Let's take some abstract streams for example and imagine you want to provide encryption and compression services over them.
With decorator you have (pseudo code):
Stream plain = Stream(); Stream encrypted = EncryptedStream(Stream()); Stream zipped = ZippedStream(Stream()); Stream zippedEncrypted = ZippedStream(EncryptedStream(Stream()); Stream encryptedZipped = EncryptedStream(ZippedStream(Stream());
With inheritance, you have:
class Stream() {...} class EncryptedStream() : Stream {...} class ZippedStream() : Stream {...} class ZippedEncryptedStream() : EncryptedStream {...} class EncryptedZippedStream() : ZippedStream {...}
1) with decorator, you combine the functionality at runtime, depending on your needs. Each class only takes care of one facet of functionality (compression, encryption, ...)
2) in this simple example, we have 3 classes with decorators, and 5 with inheritance. Now let's add some more services, e.g. filtering and clipping. With decorator you need just 2 more classes to support all possible scenarios, e.g. filtering -> clipping -> compression -> encription. With inheritance, you need to provide a class for each combination so you end up with tens of classes.
In reverse order:
2) With, say, 10 different independent extensions, any combination of which might be needed at run time, 10 decorator classes will do the job. To cover all possibilities by inheritance you'd need 1024 subclasses. And there'd be no way of getting around massive code redundancy.
1) Imagine you had those 1024 subclasses to choose from at run time. Try to sketch out the code that would be needed. Bear in mind that you might not be able to dictate the order in which options are picked or rejected. Also remember that you might have to use an instance for a while before extending it. Go ahead, try. Doing it with decorators is trivial by comparison.
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