So, you want to extend behavior but want to avoid subclassing? Then the Decorator Pattern is for you. Decorators change behavior by adding new functionality to the components they decorate without modifying those components. This pattern is based on the Open-Closed OO principle:
Let's review each class from the above diagram:
OK, that's kind of confusing, I know. Let's see a real example of the Decorator pattern in action so you can understand the concept. If you have used the java.io API you have already used this pattern, just think about opening streams from a file:
The last piece of code is making use of the Decorator Pattern, it is decorating a java.io.FileInputStream so we can read primitive Java data types instead of bytes. Let's review the most important points:
As you can see, every decorator adds behavior to a component (in this case to a FileInputStream so it can read primitive Java data types). The following diagram was generated using Architexa's Free Tool for Understanding Code and it shows the relations between the input-stream classes we were talking about (and some others) and we can see the exact same structure of the Decorator Pattern:
Something to be aware of is that every decorator is another class in your design, so if you have a lot of decorators, your design will have a lot of small classes and it may become complex.
One last thing, remember the most important OO Principle of all: Always use the simplest solution that meets your needs, even if it doesn't include a pattern.
See ya!
Classes should be open for extension but closed for modification.Designs must be flexible and opened for behavior extension but without modifications to existing code. That way, you avoid introducing new bugs to previous tested and reliable code. Let's check the definition of the Decorator pattern, according to the Head First Design Patterns book:
Attach additional responsabilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.And the basic class diagram for this pattern is as follows:
Let's review each class from the above diagram:
- Component: Most of the time it's an abstract class with abstract methods. Represents the base class of the hierarchy.
- ConcreteComponent: Concrete class that implements the methods from the abstract Component class, during the implementation of the methods you should define default behavior. It's the real class you want to decorate. You may have as many ConcreteComponent classes as you need.
- Decorator: Base class for decorators, it's abstract so decorators are required to implement the abstract methods. It's composed with a reference to the Component class, so decorators may access the object they are decorating. Notice that both ConcreteComponent and Decorator subclass the Component class, that way decorators may be transparent to you, I mean, you are going to have a reference to a Component object and it may or may not be decorated, you just don't know (or care).
- ConcreteDecorator: A concrete decorator that implements the methods from the abstract Decorator class. It's the class that executes the real job of decorating. It can access the object it is decorating. You can have as many ConcreteDecorator classes as you need.
OK, that's kind of confusing, I know. Let's see a real example of the Decorator pattern in action so you can understand the concept. If you have used the java.io API you have already used this pattern, just think about opening streams from a file:
//in a class... public void printLines(String file) throws Exception { DataInputStream rin = null; rin = new DataInputStream(new FileInputStream(file)); //more code... }
The last piece of code is making use of the Decorator Pattern, it is decorating a java.io.FileInputStream so we can read primitive Java data types instead of bytes. Let's review the most important points:
- java.io.InputStream: Reads bytes. Base class of the input-streams of bytes hierarchy. This is our Component class. It is not present in our code.
- java.io.FileInputStream: Reads bytes from a file. This is our ConcreteComponent class as it extends the java.io.InputStream.
- java.io.FilterInputStream: Base class for decorators. It is not present in our code.
- java.io.DataInputStream: Reads primitive Java data types.
As you can see, every decorator adds behavior to a component (in this case to a FileInputStream so it can read primitive Java data types). The following diagram was generated using Architexa's Free Tool for Understanding Code and it shows the relations between the input-stream classes we were talking about (and some others) and we can see the exact same structure of the Decorator Pattern:
Something to be aware of is that every decorator is another class in your design, so if you have a lot of decorators, your design will have a lot of small classes and it may become complex.
One last thing, remember the most important OO Principle of all: Always use the simplest solution that meets your needs, even if it doesn't include a pattern.
See ya!
References:
Freeman Eric and Freeman Elisabeth and Sierra Kathy and Bates Bert (2004). Head First Design Patterns. United States of America: O'Reilly Media, Inc.
I am very happy to be here because this is a very good site that provides lots of information about the topics covered in depth. Im glad to see that people are actually writing about this issue in such a smart way,
ReplyDelete