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

Dynamic Decorator Pattern

, 30 Sep 2010
Rate this:
Please Sign up or sign in to vote.
Extend functionality of an object without modifying its class or writing decoration code during design time

Introduction

This article describes a Dynamic Decorator pattern, which can be used to add extra functionality to an object dynamically. The Dynamic Decorator makes use of .NET remoting and reflection technologies. It gets rid of the design time work needed in the traditional Decorator pattern (one of GoF patterns). It is very flexible and has great advantages when new functionality needs to be added to object methods.

Background

While using the GoF Decorator pattern, we need to design decoration code at compile time. I found it difficulty to maintain the code while requirements evolve and new features are added. I thought that it would be nice to have an easier and maintenance free way to extend functionality of an object. It led me to have the idea of Dynamic Decorator.

Using the Code

At the core of Decorator pattern is that new functionality can be added to object methods without modifying the class from which the object is instantiated. Say, your software has a well tested class Employee, which implements an IEmployee interface as follows.

public interface IEmployee
{
    System.Int32? EmployeeID { get; set; }
    System.String FirstName { get; set; }
    System.String LastName { get; set; }
    System.DateTime DateOfBirth { get; set; }
    System.String FullName();
    System.Single Salary();
}
public class Employee : IEmployee
{
    #region Properties

    public System.Int32? EmployeeID { get; set; }
    public System.String FirstName { get; set; }
    public System.String LastName { get; set; }
    public System.DateTime DateOfBirth { get; set; }

    #endregion

    public Employee(
        System.Int32? employeeid
        , System.String firstname
        , System.String lastname
        , System.DateTime bDay
    )
    {
        this.EmployeeID = employeeid;
        this.FirstName = firstname;
        this.LastName = lastname;
        this.DateOfBirth = bDay;
    }

    public Employee() { }

    public System.String FullName()
    {
        System.String s = FirstName + " " + LastName;
        Console.WriteLine("Full Name: " + s);
        return s;
    }

    public System.Single Salary()
    {
        System.Single i = 10000.12f;
        Console.WriteLine("Salary: " + i);
        return i;
    }
}

After release of your software, some customers want security right check before calling the Salary method. And you think it would be useful to put some log information before and after method calls for debugging and support purposes.

There are several ways you can implement these new features and requirements. You can modify your Employee class directly to add these new features. Or you can use the GoF's Decorator pattern to create some decoration classes for objects of Employee. Or you can use the Dynamic Decorator. The source code of an implementation of Dynamic Decorator can be found in the zip file.

Here, I am going to demonstrate how the Dynamic Decorator can be used to achieve it at runtime without modifying Employee class or creating decoration classes. The following code is all you need to add security check and log to methods of an object of Employee.

static void Main(string[] args)
{
    IEmployee em = new Employee(1, "John", "Smith", new DateTime(1990, 4, 1));
    IEmployee tpCheckRight = (IEmployee)ObjectProxyFactory.CreateProxy(
        em,
        new String[] { "Salary" },
        new Decoration(new DecorationDelegate(UserRightCheck), null), 
        null);

    IEmployee tpLogCheckRight = (IEmployee)ObjectProxyFactory.CreateProxy(
        tpCheckRight,
        new String[] { "Salary", "FullName" },
        null, 
        new Decoration(new DecorationDelegate(ExitLog), null));

    try
    {
        tpLogCheckRight.FullName();
        Console.WriteLine("");
        tpLogCheckRight.Salary();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

private static void UserRightCheck(object target, object[] parameters)
{
    Console.WriteLine("Do security check here");
}

private static void ExitLog(object target, object[] parameters)
{
    Console.WriteLine("Do exit log here");
}

In the above code, an instance of Employee, em, is created. Then, ObjectProxyFactory.CreateProxy is called with em object as the first parameter. The second parameter is a string array which includes names of the object methods to which you want additional functionality to be added, { "Salary" }, for this case. The third parameter is a Decoration instance. The logic implemented in its delegate will be executed prior to the method calls specified in the second parameter. For this case, the UserRightCheck method is passed to the delegate with no parameter, and it will be executed prior to Salary method call. The fourth parameter is the other Decoration instance. The logic implemented in its delegate will be executed after the method calls specified in the second parameter. For this case, there is no logic that needs to be executed after Salary method call.

The call of ObjectProxyFactory.CreateProxy returns a proxy of em object, tpCheckRight. From now on, you can use tpCheckRight just like the em object. For instance, if you call Salary method using tpCheckRight, the UserRightCheck will be executed, and then em's Salary method.

In the above code, we pass tpCheckRight in a second ObjectProxyFactory.CreateProxy call in order to add ExitLog logic after execution of Salary and FullName methods of the em object.

When execution of the above code, you will see the following output:

Full Name: John Smith
Do exit log here

Do security check here
Salary: 10000.12
Do exit log here

As you can see, the ExitLog logic is called after the actual method calls of the object while the UserRightCheck is called before the actual method call of the object.

Points of Interest

New features are added to object methods on the fly without changing the original class.

No groundwork at design time is needed comparing to the GoF's Decorator pattern.

Better design can be achieved by not mingling various features into a mighty class (separation of concerns).

What's Next

In the article, Add Aspects to Object Using Dynamic Decorator, I dive into more details on Dynamic Decorator's important features and discuss how to add aspects to object at runtime and enhance them using Dynamic Decorator.

License

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

Share

About the Author

Gary H Guo

United States United States
Object-oriented (OO) is about "classes" not "objects". But I truly believe that "objects" deserve more our attentions. If you agree, read more on... Dynamic Object Programming (DOP), Component-Based Object Extender (CBO Extender), AOP Container and Dynamic Decorator Pattern.
 
Mobile development is not just another type of front end. The real challenge is actually in the back end: How to present meaningful information in time to mobile users with exponentially increased data flooding around? Here is my first mobile solution: SmartBars - Barcode Reader, Price Comparison and Coupons.
 
Gary lives in southeast Michigan. My first programming language is FORTRAN. For the last a few years, I have primarily focused on .NET technologies with Mobile Development as my newest interest.

Comments and Discussions

 
Questionwhats objectproxyfactory? PinmemberRahman Mahmoodi28-Oct-13 20:46 
AnswerRe: whats objectproxyfactory? PinmemberGary H Guo1-Nov-13 10:42 
GeneralMy vote of 3 PinmemberStefan_Lang16-Jan-13 21:24 
GeneralMy vote of 4 Pinmembersmcilwain8-Sep-11 3:00 
GeneralRe: My vote of 4 Pinmembersmcilwain8-Sep-11 3:05 
GeneralRe: My vote of 4 PinmemberGary H Guo8-Sep-11 4:40 
QuestionHow can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberJohn_Kattenhorn13-Feb-11 7:04 
AnswerRe: How can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberGary H Guo14-Feb-11 3:32 
Hi John,
 
Your questions are answered in my next article (tentative title "Components, Aspects and Dynamic Decorator"). It will be published in next week or so. Please stay tuned.
 
Here are the short answers to your questions. The Dynamic Decorator can be applied to any interface. Therefore, no base interface is needed. You can call Dynamic Decorator whenever you need. There is no start up services concept.
 
You are on the right path in terms of design your cross-cutting concerns (logging, instrumentation). Design these aspects as global methods, and apply them to objects in your application. My next article will give examples how it can be done.
 
Thanks for your patiency.
 
Gary
GeneralRe: How can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberJohn_Kattenhorn14-Feb-11 7:14 
GeneralRe: How can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberGary H Guo14-Feb-11 16:35 
GeneralRe: How can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberGary H Guo18-Feb-11 3:24 
GeneralRe: How can i use the Dynamic Decorator Pattern to provide Application Services across the whole application PinmemberGary H Guo2-Sep-11 10:05 
QuestionWill it be persisting for all instance of the object ? Pinmembersoftty27-Aug-10 18:55 
AnswerRe: Will it be persisting for all instance of the object ? PinmemberGary H Guo28-Aug-10 2:05 
GeneralRe: Will it be persisting for all instance of the object ? Pinmembersoftty28-Aug-10 2:59 
GeneralRe: Will it be persisting for all instance of the object ? PinmemberGary H Guo30-Aug-10 3:07 
GeneralYou should take advantages of Lanbda PinmemberMunim Abdul26-Aug-10 20:47 
GeneralRe: You should take advantages of Lanbda PinmemberGary H Guo27-Aug-10 6:47 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 30 Sep 2010
Article Copyright 2010 by Gary H Guo
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid