Background
Again, my favorite place - Elizabeth's daycare center.
In Elizabeth's daycare center, there are many reward programs for the kids each week. For example: three types of awards are given to kids for their achievements at the end of each week. Depending on how the kids perform each week, the kids could have different prizes:
- All the kids will have a sticker at the end of the week as a prize.
- A kid could have a certificate posted on his/her cubicle if the kid passed potty training.
- The kid could also have a free book when she/he becomes the KID of the WEEK.
Remember, kids may have different prizes at the end of each week. It really depends on what the kid has done that week. That means the awards are dynamically added to the kids every week, and they can also be removed the next week.
Introduction
The Decorator design could help us when we try to expend the additional works for a particular activity. Based on different levels (or conditions) of the same object, we may want to expend the decoration for the same method. For example: a one year old baby will smile when she is happy. Once she is 2 years old, she could smile and jump to express her happiness. When she is 3 years old, she could smile, jump, and also talk when she is happy. However from the client side, the client will not notice what additional process has been attached when consuming an object. The client only knows the baby is happy, how the baby describes himself/herself as happy will depend on his/her age.
Decorator Design Pattern Structure
Class Diagram
Implementation Code
Component Classes
Kid
The Kid
class is an abstract
base component, it has an abstract
method to show all the prizes for a kid.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace Decorator
{
public abstract class Kid
{
public string Name { get; set; }
public abstract void ShowMyPrizes();
}
}
}
GoodKid
GoodKid
is the concrete component class that inherits from the Kid
class. It actually provides the default implementation for ShowMyPrizes()
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace Decorator
{
public class GoodKid : Kid
{
public override void ShowMyPrizes()
{
Console.WriteLine("My name is {0} .
I am a good kid! I get a sticker this week", Name);
}
}
}
}
Decorator Classes
KidDecorator
The KidDecorator
contains a Kid
object that will allow the Decorator
class to extend the default method (in this case, it would be ShowMyPrizes()
). It's an abstract
class that only provides the basic protocol; a concrete Decorator
class has to be developed to implement the extension details.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace Decorator
{
public abstract class KidDecorator : Kid
{
Kid aKid;
public KidDecorator(Kid kid)
{
aKid = kid;
}
public override void ShowMyPrizes()
{
aKid.ShowMyPrizes();
}
}
}
}
PottyTrainedKid and KidofWeek_Kid
PottyTrainedKid
and KidofWeek_Kid
are the concrete Decorator
classes to plug the additional works into the default method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace Decorator
{
public class PottyTrainedKid : KidDecorator
{
public PottyTrainedKid(Kid aKid)
: base(aKid)
{
}
public override void ShowMyPrizes()
{
base.ShowMyPrizes();
ShowMyExtendPrize();
}
private void ShowMyExtendPrize()
{
Console.WriteLine("Since I am a potty trained kid, " +
"I also have an certificate stamped on my cube for this week");
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace www.askbargains.com
{
namespace Decorator
{
public class KidofWeek_Kid : KidDecorator
{
public KidofWeek_Kid(Kid aKid)
: base(aKid)
{
}
public override void ShowMyPrizes()
{
base.ShowMyPrizes();
ShowMyAdditionalPrize();
}
private void ShowMyAdditionalPrize()
{
Console.WriteLine("Since I am a kid of this month, I also " +
"have a free book as a prize for this week");
}
}
}
}
Client App
From my client application, I simulate a Use Case as below.
In the first week, Elizabeth is just a good kid. In the second week, Elizabeth passes the potty training program. In the third week, Elizabeth passes the potty training program and also becomes kidofweek
. In the fourth month, she is again kidofweek
, but doesn't pass the potty training again.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.Decorator;
namespace www.askbargains.com
{
namespace Client
{
class Program
{
static void Main(string[] args)
{
GoodKid Elizabeth = new GoodKid();
Elizabeth.Name = "Elizabeth";
DisplayReport(Elizabeth, "This is first week.");
Kid pottyKid = new PottyTrainedKid(Elizabeth);
DisplayReport(pottyKid, "This is second week.");
Kid kidofweek = new KidofWeek_Kid(pottyKid);
DisplayReport(kidofweek, "This is third week.");
Kid newKid = new KidofWeek_Kid(Elizabeth);
DisplayReport(newKid, "This is fourth week.");
Console.Read();
}
private static void DisplayReport(Kid anyKid, string weekMessage)
{
Console.WriteLine(weekMessage);
anyKid.ShowMyPrizes();
}
}
}
}
Once you execute the client app, you can see all the prizes for each week that Elizabeth has earned. Cool!
Conclusion
In this article, I demonstrated how we can use the Decorator Pattern to achieve the implementation for a daycare reward system. I also used the daycare center for the Chain of Responsibility Pattern in my other article.
History
- 2 September, 2009: Initial post.