decorator design pattern (a gift wrapper)
DESCRIPTION
This presentation will help in understanding decorator design pattern, it’s structure and it’s implementation.TRANSCRIPT
Decorator Design PatternA Gift Wrapper
Sameer Singh Rathoud
About presentation
This presentation will help in understanding decorator design pattern, it’s
structure and it’s implementation.
I have tried my best to explain the concept in very simple language.
The programming language used for implementation in this presentation is c#. But
any one from different programming background can easily understand the
implementation.
Definition
A decorator pattern is a design pattern that allows behavior to be added to an
object dynamically. Decorators provide a flexible alternative to sub-classing for
extending functionality.
Decorator pattern is a structural design pattern.
Problem
A car manufacturing company named “UselessCars” came newly in the market. Initially they came up
with a very basic cars with four wheels, a engine and few more basic things.
UselessCarBasic
getCost()
This is a class for our
“UselessCarBasic” with an operation
“getCost()” (will return the cost of
the car).
Problem
As the company was not able to sell the cars. They came up with few more features in the car like
“doors” and “seats”.
UselessCarBasic
getCost()
So the “UselessCars” came up with three more classes
“UselessCarWithDoor”, “UselessCarWithseats” and
“UselessCarWithDoorAndSeats” deriving from “UselessCarBasic”.
Here each derive class has implemented operation “getCost()”Inheritance
UselessCarWithDoor
getCost()
UselessCarWithseats
getCost()
UselessCarWithDoorAndSeats
getCost()
Problem
But later the company came up with lots of other features and “UselessCars” class structure met
with the class explosion.
UselessCarBasic
getCost()
Inheritance
UselessCarWithDoor
getCost()
UselessCarWithseats
getCost()
UselessCarWithABS
getCost()
UselessCarWith
AdjustableSeat
getCost()
UselessCarWith
FogLamp
getCost()
UselessCarWithAirBag
getCost()
UselessCarWithMusicSys
getCost()
UselessCarWithDoorAndSeats
getCost()
Problem
To solve this class explosion problem the “UselessCar” has changed there structure to a single class
and added operations to add the cost of each features.
UselessCarBasic
AddDoors()
AddSeats()
AddABS()
AddLeatherSeatCovers()
AddLeatherDashBoard()
AddMusicSystem()
AddAirBags()
....
getCost()
Although this is a workable solution. But this class structure is
violating the OO design principle “open/close principle” (open
for extension and close for modification). In this class
structure, every time a new feature is getting launched
“UselessCarBasic” class will get changed (adding a function in
class for adding cost). So we need to look for a better solution
to this problem.
Solution
Inheritance
<< interface >>
UselessCar
GetCost()
UselessCarBasic
Inheritance
UselessCar
GetCost()
<< interface >>
UselessCarDecorator
GetCost()
UselessCarWithDoors
GetCost()
UselessCarWithDoors
GetCost()
UselessCarWithABS
GetCost()
UselessCarWithFogLamps
GetCost()
....
GetCost()
In this approach we have created an
interface “UselessCar” which is having
an operation “GetCost()” and created a
class “UselessCarBasic” which is
implementing “UselessCar” and defining
operation “GetCost()”. Here we have
introduced one more interface
“UselessCarDecorator” which is holding a
reference of “UselessCar” and all the
features of “UselessCar” will be
implementing this interface and
providing the definition of operation
GetCost() by adding the cost of the
feature in the cost of “UselessCarBasic”.
Motivation and Intent
• The intent of this pattern is to add additional responsibilities dynamically to an
object.
Add addition functionality or state to an individual objects at run-time. Inheritance
is not feasible because it is static and applies to an entire class.
Structure
Client
Inheritance
<< interface >>
Component
Operation ()
Operation ()
Concrete Component
Operation ()
<< interface >>
Decorator
Concrete Decorator A
Operation ()
Concrete Decorator B
Operation ()
Inheritance
state AddedBehavior ()
Component
Participants in structure
• Component (interface): is a interface for objects for which responsibilities can be added
dynamically.
• Concrete component: concrete implementation of component and will provide the object for
which responsibilities can be added at runtime.
• Decorator (interface): is a interface for additional functionality or state and maintains the
reference to component.
• Concrete decoratorA and Concrete decoratorB: are the classes defining the implementation to
decorator interface and provide the additional functionality.
• Client: The user of the decorator design pattern.
Collaborations
• Created a Component and run the Operation() on that. Added a behavior/functionality/state with
concrete component and run the operation on the decorated object, now the behavior will get
changed.
Client Concrete Component Concrete Decorator
new Concrete Component ()
ComponentObject.Operation()
new Concrete Decorator (ComponentObject)
ConcreteDecoratorObject.Operation()
Implementation (C#)
Component (Interface)
public abstract class UselessCar
{
public abstract int Cost { get; }
}
Here “UselessCar” is an abstract class with
an abstract property “Cost”. Now all the
concrete classes implementing this abstractclass will override “Cost” method.
<< interface >>
UselessCar
+ Cost ()
Implementation (C#)Concrete Component
class UselessCarBasic: UselessCar
{
public override int Cost
{
get
{
return 1000; //Basic Car Cost
}
}
}
Here a concrete class “UselessCarBasic” is
implementing abstract class “UselessCar”
and these concrete classes is overridingproperty “Cost” (giving the cost of
“UselessCarBasic”) of “UselessCar”
class.
<< interface >>
UselessCar
+ Cost ()
UselessCarBasic
Cost()
Implementation (C#)Decorator (interface)
public abstract class UselessCarDecorator : UselessCar
{
public UselessCar uselessCarObj;
public override int Cost
{
get
{
return this.uselessCarObj.Cost;
}
}
public UselessCarDecorator(UselessCar uselessCar)
{
this.uselessCarObj = uselessCar;
}
}
Here an abstract class “UselessCarDecorator”
is implementing abstract class “UselessCar” and
these concrete classes is overriding property“Cost” of “UselessCar” class and additionally
it is holding a reference of “UselessCar”.
<< interface >>
UselessCar
+ Cost ()
UselessCarBasic
+ Cost()
UselessCarDecorator
+ Cost()
+ UselessCar
Implementation (C#)Concrete Decorator
class UselessCarWithDoors: UselessCarDecorator {
public UselessCarWithDoors(UselessCar uselessCar)
: base(uselessCar) {
}
public override int Cost {
get {
return uselessCarObj.Cost + 200; //Basic Car Cost + Doors cost
}
}
}
“UselessCarWithDoors”
is a concrete class
implementing abstract class“UselessCarDecorator”
and overriding property“Cost” of
“UselessCarDecorator”
and it is defining a constructor
expecting a parameter of type“UselessCar” this
parameter is further passed to
the constructor of base class(“UselesscarDecorator”).
Implementation (C#)
class UselessCarWithSeats : UselessCarDecorator {
public UselessCarWithSeats(UselessCar uselessCar)
: base(uselessCar) {
}
public override int Cost {
get {
return uselessCarObj.Cost + 150; //Basic Car Cost + Seats cost
}
}
}
Here is an another class“UselessCarWithSeats”
implementing“UselessCarDecorator”
and overriding property“Cost” and it is also defining
a constructor expecting a
parameter of type“UselessCar” this
parameter is further passed to
the constructor of base class(“UselesscarDecorator”).
Concrete Decorator
Implementation (C#)
class UselessCarWithABS : UselessCarDecorator {
public UselessCarWithABS(UselessCar uselessCar)
: base(uselessCar) {
}
public override int Cost {
get {
return uselessCarObj.Cost + 800; //Basic Car Cost + ABS cost
}
}
}
This is one more class“UselessCarWithABS”
implementing“UselessCarDecorator”
and overriding property “Cost”
and it is also defining a
constructor expecting a
parameter of type“UselessCar” this parameter
is further passed to the
constructor of base class(“UselesscarDecorator”).
Concrete Decorator
Implementation (C#)Client
class Client {
static void Main(string[] args) {
UselessCar uselessCar = new UselessCarBasic();
System.Console.WriteLine(uselessCar.Cost);
UselessCarWithDoors uselessCarWithDoors = new UselessCarWithDoors(uselessCar);
System.Console.WriteLine(uselessCarWithDoors.Cost);
UselessCarWithSeats uselessWithCarDoorsandSeats = new UselessCarWithSeats(uselessCarWithDoors);
System.Console.WriteLine(uselessWithCarDoorsandSeats.Cost);
UselessCarWithABS uselessCarWithABS = new UselessCarWithABS(uselessCar);
System.Console.WriteLine(uselessCarWithABS.Cost);
}
}
For using decorator design pattern the client will create an instance of “UselessCarBasic” and
can add as many features as he wants to by creating the object of features by passing the referenceof “UselessCar” and can perform operation “Cost” on those feature objects.
Implementation (C#)Class Structure << interface >>
UselessCar
+ Cost ()
UselessCarBasic
+ Cost()
UselessCarDecorator
+ Cost()
+ UselessCar
UselessCarWithABS
+ Cost()
UselessCarWithDoors
+ Cost()
UselessCarWithSeats
+ Cost()
Inheritance
Inheritance
Client
Example and applicability
GUI framework: GUI framework can use decorator pattern for extending the functionality
dynamically.
Whenever a programmer is having a requirement where he/she has to extend the functionality at
runtime on the top of some basic functionality can opt for decorator design pattern.
References
1. Design Patterns: Elements of Reusable Object-Oriented Software
• by Ralph Johnson, John Vlissides, Richard Helm, and Erich Gamma
2. Head First Design Patterns
• Kathy Sierra, Eric Freeman, Elisabeth Freeman, Bert Bates
End of Presentation . . .