Click here to Skip to main content
Click here to Skip to main content
Go to top

Decorator

, 11 Oct 2013
Rate this:
Please Sign up or sign in to vote.
The Decorator patterns allows an objects behavior to be dynamically altered at runtime.This change in behavior is accomplished by wrapping an

Editorial Note

This articles was originally at wiki.asp.net but has now been given a new home on CodeProject. Editing rights for this article has been set at Bronze or above, so please go in and edit and update this article to keep it fresh and relevant.

The Decorator patterns allows an objects behavior to be dynamically altered at runtime.

This change in behavior is accomplished by wrapping an object with a new object.  This new wrapper object is the Decorator. The Decorator object will implement the same interface as the object being wrapped.  Because the decorated object uses the same interface as an undecorated object, other parts of your system do not need to be aware of whether or not one or more decorations are in use.

The decorator (wrapper) can now alter the behavior of the object being wrapped by either completely replacing various methods or by altering the behavior of the methods of the object being decorated.

Example

A simple example of a Decorator can be demonstrated with a report class.  Some reports may need a header and some may also need a footer.  Still others might require both a header and a footer.

First, since the Decorator needs to implement the same interface as the object being decorated, let's define an Interface.

Public Interface IReport

    Sub Print()

End Interface

Now we can create a very simple report class that implements that interface.

Public Class Report

    Implements IReport

 

    Public Sub Print() Implements IReport.Print

        HttpContext.Current.Response.Write("This is the report body.")

    End Sub

End Class

Next we can create a Decorator class to add a header to our report. Since our Decorator will wrap around our report, it requires that a report instance is passed to its constructor.

Public Class ReportHeaderDecorator

    Implements IReport

 

    Private _innerReport As IReport

 

    Public Sub New(ByVal innerReport As IReport)

        'save a reference to the object being decorated

        _innerReport = innerReport

    End Sub

 

    Public Sub Print() Implements IReport.Print

        'add header decoration first

        HttpContext.Current.Response.Write("<h3>This is the report header</h3>")

        HttpContext.Current.Response.Write("<hr />")

 

        'now let the report being decorated do its printing

        _innerReport.Print()

    End Sub

End Class

We can also create another Decorator to add a footer to our report.

Public Class ReportFooterDecorator

    Implements IReport

    'save a reference to the object being decorated

    Private _innerReport As IReport

 

    Public Sub New(ByVal innerReport As IReport)

        _innerReport = innerReport

    End Sub

 

    Public Sub Print() Implements IReport.Print

 

        'let the report being decorated do its printing first

        _innerReport.Print()

 

        'now we add the footer decoration

        HttpContext.Current.Response.Write("<hr />")

        HttpContext.Current.Response.Write("<h6>This is the report footer.</h6>")

 

    End Sub

Since the Report class and the decorators all implement the same IReport Interface, regular reports and decorated reports can be used anywhere that an IReport is accepted.  Here is how we can create a report and then wrap it with the decorators.

Dim myReport As IReport

myReport = New Report 'create the basic report

myReport = New ReportHeaderDecorator(myReport) 'wrap with a header decoration

myReport = New ReportFooterDecorator(myReport) 'wrap with a footer decoration

 

myReport.Print()

 

The result of printing this report will look something like this:

This is the report header


This is the report body.
This is the report footer.

 

A similar effect could by achieved through sub-classing. This would require 3 subclasses of our Report class.  A ReportWithHeader subclass, a ReportWithFooter subclass and also a ReportWithHeaderAndFooter subclass.  As more and more decorations are needed, it quickly becomes unmanageable to create all the needed subclasses to cover all the possible combinations.

Since the various Decorator classes can be combined at runtime, we do not have to predefine all the possible combinations.

 

For C#, the sample code would look like this:

public interface IReport

{

    void Print();

}

 

public class Report : IReport

{

    public void IReport.Print()

    {

        HttpContext.Current.Response.Write("This is the report body.");

    }

}

public class ReportHeaderDecorator : IReport

{

    private IReport _innerReport;

    public ReportHeaderDecorator(IReport innerReport)

    {

        //save a reference to the object being decorated

        _innerReport = innerReport;

    }

    public void IReport.Print()

    {

        //add header decoration first

        HttpContext.Current.Response.Write("<h3>This is the report header</h3>");

        HttpContext.Current.Response.Write("<hr />");

 

        //now let the report being decorated do its printing

        _innerReport.Print();

    }

}

public class ReportFooterDecorator : IReport

{

    //save a reference to the object being decorated

    private IReport _innerReport;

    public ReportFooterDecorator(IReport innerReport)

    {

        _innerReport = innerReport;

    }

    public void IReport.Print()

    {

 

        //let the report being decorated do its printing first

        _innerReport.Print();

 

        //now we add the footer decoration

        HttpContext.Current.Response.Write("<hr />");

        HttpContext.Current.Response.Write("<h6>This is the report footer.</h6>");

 

    }

}

 

 

 

//implementing the decorator

IReport myReport;

myReport = new Report();

//create the basic report

myReport = new ReportHeaderDecorator(myReport);

//wrap with a header decoration

myReport = new ReportFooterDecorator(myReport);

//wrap with a footer decoration

 

myReport.Print();

 

License

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

Share

About the Author

ASP.NET Community

United States United States
The ASP.NET Wiki was started by Scott Hanselman in February of 2008. The idea is that folks spend a lot of time trolling the blogs, googlinglive-searching for answers to common "How To" questions. There's piles of fantastic community-created and MSFT-created content out there, but if it's not found by a search engine and the right combination of keywords, it's often lost.
 
The ASP.NET Wiki articles moved to CodeProject in October 2013 and will live on, loved, protected and updated by the community.
Group type: Collaborative Group

247 members


Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140926.1 | Last Updated 11 Oct 2013
Article Copyright 2013 by ASP.NET Community
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid