Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Decorator

0.00/5 (No votes)
2 Apr 2010 1  
The Decorator patterns allows an objects behavior to be dynamically altered at runtime.This change in behavior is accomplished by wrapping an

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here