Click here to Skip to main content
Click here to Skip to main content

Decorator Design Pattern

By , 8 Sep 2009
 

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:

  1. All the kids will have a sticker at the end of the week as a prize.
  2. A kid could have a certificate posted on his/her cubicle if the kid passed potty training.
  3. 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

Decorator.JPG

Class Diagram

Decorator_Class.JPG

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
    {
        //Concreate Kid
        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
        {
            //an instance of kid. 
            Kid aKid;

            public KidDecorator(Kid kid)
            {
                aKid = kid;
            }

            //show the deafult prize for aKid object
            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()
            {
                //call base(deafault) method.
                base.ShowMyPrizes();
                //addtional method
                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()
            {
                //call base(deafault) method.
                base.ShowMyPrizes();
                //addtional method
                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)
            {

                //Kid Elizabeth is created
                GoodKid Elizabeth = new GoodKid();
                Elizabeth.Name = "Elizabeth";

                //First week. Elizabeth is a good kid only. She deserve her default prize.
                DisplayReport(Elizabeth, "This is first week.");

                //In the second week, Elizabeth pass the potty training.
                Kid pottyKid = new PottyTrainedKid(Elizabeth);
                DisplayReport(pottyKid, "This is second week.");

                //In the third week, Elizabeth is both potty trained
                //and kid of the week,
                //She will have default , potty trained and kidofweek prizes.
                Kid kidofweek = new KidofWeek_Kid(pottyKid);
                DisplayReport(kidofweek, "This is third week.");


                //In the four week, Elizabeth is kid of the week,
                //She will have default and kidofweek prizes.
                Kid newKid = new KidofWeek_Kid(Elizabeth);
                DisplayReport(newKid, "This is fourth week.");

                Console.Read();

            }

            //Helper method to show the report.
            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!

Decorator_output.JPG

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Allen _ Wang
Architect
United States United States
Member
Sr Software Architect.Microsoft Certified Solutions Developer (MCSD). owner of www.askbargains.com.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionDecorator Example using Order ManagermemberNilesh Gule4 Jul '12 - 5:49 
Recently I posted an entry related to Decorator pattern using Order Manager as an example.
 
http://www.nileshgule.com/2012/07/decorator-design-pattern.html[^]
www.nileshgule.com

QuestiondoubtmemberMogamboo_Khush_Hua7 Feb '12 - 1:02 
I want a new kid , who would be best kid of week as well as potty_trained kid, how i would do that ?
GeneralMy vote of 5membermaxtyrann24 Jul '10 - 6:13 
I like the article and sample code, Elizabeth's daycare center concept is great and gives the article(s) continuity and life imho.
QuestionWhy the inheritance?memberxondokan8 Sep '09 - 4:28 
Every time i see the Decorator pattern, i ask myself why the Decorator class inherits from the class it's supposed to decorate. And today i decided to go public... Why?
 
By the way... the all Elisabeth's Daycare series is excelent Wink | ;)
 
Pedro Abreu

AnswerRe: Why the inheritance?memberSmartAllen8 Sep '09 - 4:44 
The inheritance could give you an ability to extend the method which you would like to do something more in your decorator class. The method name is not change from the original class to the decorator class , but the method in the decorator class provides more details than the original class.
 

thanks.
GeneralRe: Why the inheritance?memberxondokan8 Sep '09 - 6:37 
But then, you would have to override more methods/properties like the kids Name (in this particulary case) returning the decorated object original value... In a more complex case, that could mean a lot of (what it seems to me as) redundant work and code lines. Don't you agree?
 
Pedro Abreu

GeneralRe: Why the inheritance?memberSmartAllen8 Sep '09 - 6:53 
Actually in this case, you don't override kids name. You just expend(override) the ShowMyPrize() method in your decorator classes. Somehow I agree it seems adding some redundant works in your decorator classes, but it's not. It provides a huge flexibility for the ShowMyPrize() method in this case to the both original class and decorator classes. It definitely brings a lot benefits for the client as well. Client only needs to consume the ShowMyPrize() from all the objects. thanks.
GeneralRe: Why the inheritance?memberbaruchl14 Sep '09 - 21:58 
I believe that the reason for the inheritance is to make sure that the decorator remains the same as the base class, so the consumer doesn't need to know what kind of class he is dealing with, and may provide a single behaviour for all types of "Kids" regardles the decorator (Polymorphism).
 
Busi

GeneralMy CommentsmemberKeithAMS7 Sep '09 - 23:16 
Hi, Me again
 
To my mind your client code is not showing that using decorator patterns means that client code does not need to know what type of Kid or Kid decorator is being used, all it needs is a reference to a Kid object. For example your weekly reports could be in a function, perhaps in another class, that accepts a Kid as a parameter. Creating new Kid decorators then would not break this function/class.
Also as a decorator "wraps" another object I think passing the wrapped object in the constructor improves the concept. The constructor stores the reference. Get, Set are not needed.
 
//Kid Elizabeth is created
GoodKid Elizabeth = new GoodKid();
Elizabeth.Name = "Elizabeth";
 
//First week. Elizabeth is a good kid only. She deserve her default prize.
DisplayReport(Elizabeth, "This is first week.");
 
//In the second week, Elizabeth pass the potty training.
Kid pottyKid = new PottyTrainedKid(Elizabeth);
DisplayReport(pottyKid, "This is second week.");
 
//In the third week, Elizabeth is both potty trained and kid of the week,
//She will have default , potty trained and kidofweek prizes.
Kid kidofweek = new KidofWeek_Kid(pottyKid);
DisplayReport(kidofweek, "This is third week.");
 

//In the four week, Elizabeth is kid of the week,
//She will have default and kidofweek prizes.
Kid newKid = new KidofWeek_Kid(Elizabeth);
DisplayReport(newKid, "This is fourth week.");
 
and the Display function:
private void DisplayReport(Kid anyKid, string weekMessage)
{
Console.WriteLine(weekMessage);
anyKid.ShowMyPrizes();
}
 
Just my £0.02
 
KM
 
I'm pink therefore I'm Spam

GeneralRe: My CommentsmemberSmartAllen8 Sep '09 - 3:15 
Thanks for your comments. Just like you said it does make sense to wrap the object in the decorator class to show the concept of the design pattern. And the seems the DisplayReport is handy too.
Well, I am going to modify the code and probably need to add a constructor to accept one parameter (kid) for the Decorator. Appreciate your outputs again. Laugh | :laugh:
GeneralRe: My CommentsmemberKeithAMS8 Sep '09 - 3:47 
No probs.
 
A really good book for design patterns I think is:
 
Head First Design Patterns, Erc Freeman and Elisabeth Freeman.
 
First time Ive really been able to get my head round some complicated stuff when I read that.
 
KM
 
I'm pink therefore I'm Spam

Generalgreat artice, people can learn from the interesting story !memberuwspstar20093 Sep '09 - 10:13 
great artice, people can learn from you interesting story. keep working !!!
we are waiting for the next chapter !!!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 8 Sep 2009
Article Copyright 2009 by Allen _ Wang
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid