The decorator pattern is a mechanism of taking a base implementation of a given interface as extending its behavior without modification of original implementation.
Its similar to inheriting from a base class, however it has more flexibility. For example, a decorator class can be applied to any other class that implements the same interface, there is no restriction to only extending a single base class. They can also be chained together etc...
e.g
public interface IThing
{
void AMethod()
}
public abstract class ThingDecorator : IThing
{
private IThing inner;
public ThingDecorator(IThing inner)
{
this.inner = inner;
}
public virtual void AMethod()
{
this.inner.AMethod();
}
}
Inheriting from ThingDecorator and applying your own extension to the virtual AMethod will add behavior (decorate) the inner instance that is passed in. As the inner instance is coupled to an interface it can be any implementation of that interface.
In your example, you could inherit ThingDecorator as AuditThingDecorator, and override AMethod and include Audit features before you call the base.AMethod()
This is different to just applying an attribute to a class. I think you are trying to apply behavior with an attribute. Attributes can only apply behavior to the class if there is a container, or some other part of the system that can read them and actually apply given behavior. With DataAnnotations, there are other classes that read these attributes and apply behavior (for example, within ASP.NET MVC, the DefaultModelBinder use some of the attributes to provide validation when binding the model).
This is a AOP (apsect orientated programming) approach. One way to apply this (and a way I tend to use) is to use Castle.Core and create interceptors that can automatically implement interface methods or extend virtual methods and read attributes from the Methods/properties that are intercepting, and then apply behavior:
http://docs.castleproject.org/Tools.DynamicProxy-Introduction.ashx
They are both essentially proxies of a given type, however the Decorator pattern above is not dynamic, they are created within code, and the AOP approach can apply behavior at runtime.