Decorator Pattern
The Decorator Pattern is a structural design
pattern that lets you attach additional responsibilities to an object
dynamically. Decorators provide a flexible alternative to subclassing for
extending functionality.
In Java, the Decorator Pattern is used to wrap objects in
decorator classes that add new behaviors or responsibilities without changing
the original object's code.
Intent
- Attach
additional responsibilities to an object dynamically.
- Provide
a flexible alternative to subclassing for extending functionality.
- Keep
the core object and its extensions separate.
- Enable
adding features transparently to clients.
Participants
The main participants in the Decorator Pattern are:
a. Component (interface or abstract class)
- Defines
the interface for objects that can have responsibilities added to them
dynamically.
- Example:
Text interface with getContent() method.
b. ConcreteComponent (implements Component)
- The
core object to which additional responsibilities can be attached.
- Example:
SimpleText class that implements Text.
c. Decorator (abstract class or interface implementing
Component)
- Maintains
a reference to a Component object.
- Implements
the Component interface.
- Delegates
operations to the wrapped component.
- Acts
as a base class for concrete decorators.
d. ConcreteDecorator (extends Decorator)
- Adds
responsibilities to the component.
- Overrides
component methods to provide extra behavior.
- Example:
UpperCaseDecorator and StarDecorator.
Uml
How it Works
- The
client interacts with objects through the Component interface.
- A ConcreteComponent
is created, which implements the basic behavior.
- To add
functionality, a Decorator wraps the ConcreteComponent.
- Multiple
decorators can wrap the same component to combine behaviors.
- Decorators
forward requests to the wrapped component, adding extra processing before
or after forwarding.
Benefits (Advantages)
- Open/Closed
Principle: You can add new behavior without modifying existing code.
- Flexible
extension: New functionality can be added at runtime.
- Avoids
an explosion of subclasses by combining decorators instead of subclassing.
- Can
wrap multiple decorators to compose complex behavior.
- Transparent
to the client — clients use decorated objects via the same interface.
Drawbacks (Disadvantages)
- Can
produce a large number of small classes.
- The
design can become complex if many decorators are stacked.
- Debugging
can be harder because of many layers of wrapping.
- Slight
performance overhead due to multiple levels of indirection.
Typical Use Cases in Java
- Adding
features to streams (java.io package uses Decorator pattern extensively: BufferedReader,
InputStreamReader).
- GUI
frameworks for adding borders, scrollbars, or behaviors to components.
- Adding
responsibilities such as logging, caching, validation dynamically.
- Adding
filters or transformations to data streams or collections.
Real-world Example (Java IO)
Java’s IO library is a classic example of the Decorator
Pattern:
- InputStream
is the Component.
- FileInputStream
is a ConcreteComponent.
- BufferedInputStream
is a Decorator adding buffering.
- DataInputStream
is another Decorator adding data-type reading.
You can wrap a FileInputStream inside a BufferedInputStream
and then wrap that in a DataInputStream to combine functionalities dynamically.
InputStream file = new
FileInputStream("file.txt");
InputStream buffer = new BufferedInputStream(file);
DataInputStream data = new DataInputStream(buffer);
int value = data.readInt();
Summary
Aspect |
Description |
Pattern Type |
Structural |
Purpose |
Add responsibilities dynamically |
Key Principle |
Composition over inheritance |
Key Benefit |
Flexible, reusable, open to extension |
Main Components |
Component, ConcreteComponent, Decorator, ConcreteDecorator |
Common Usage |
Java IO, GUI component decoration |
Example : -
Component
package decoratordesignpattern;
public interface Text {
String
getContent();
}
ConcreteComponent
package decoratordesignpattern;
public class SimpleText implements Text
{
private
String content;
public
SimpleText(String content) {
super();
this.content
= content;
}
@Override
public
String getContent() {
return
content;
}
}
Decorator
package decoratordesignpattern;
public abstract class TextDecorator implements Text {
protected
Text decoratedText;
public
TextDecorator(Text decoratedText) {
super();
this.decoratedText
= decoratedText;
}
@Override
public String
getContent() {
return
decoratedText.getContent();
}
}
ConcreteDecorator
package decoratordesignpattern;
public class UpperCaseDecorator extends TextDecorator {
public
UpperCaseDecorator(Text decoratedText) {
super(decoratedText);
}
public
String getContent() {
return
decoratedText.getContent().toUpperCase();
}
}
package decoratordesignpattern;
public class StarDecorator extends
TextDecorator {
public
StarDecorator(Text decoratedText) {
super(decoratedText);
//
TODO Auto-generated constructor stub
}
@Override
public
String getContent() {
return
"*** " + decoratedText.getContent() + " ***";
}
}
package decoratordesignpattern;
public class DecoratorDemo {
public
static void main(String[] args) {
Text
myText = new SimpleText("Hello World!");
//
Wrap with uppercase decorator
Text
upper = new UpperCaseDecorator(myText);
System.out.println(upper.getContent());
// Output: HELLO, WORLD!
//
Wrap with star decorator
Text
starred = new StarDecorator(myText);
System.out.println(starred.getContent());
// Output: *** Hello, world! ***
//
Combine decorators (starred + uppercase)
Text
starredUpper = new StarDecorator(upper);
System.out.println(starredUpper.getContent());
// Output: *** HELLO, WORLD! ***
}
}
o/p :-
HELLO WORLD!
*** Hello World! ***
*** HELLO WORLD! ***
No comments:
Post a Comment