originalmente publicado em http://50minutos.com.br/blog

Definição:

É um padrão que nos permite estender (decorar) dinamicamente as características de uma classe qualquer. Por características entendemos estado (state: campos e propriedades - propriedades somente em .Net) ou comportamento (behavior: métodos).

É uma alternativa à herança e tem uma diferença importante (e que torna o seu uso mais flexível) em relação àquela:

  • herança é definida em tempo de compilação;
  • uma classe decorada é definida em tempo de execução.

Quando usar:

  • Quando temos uma classe que não queremos herdar;
  • Quando temos uma classe que não pode ser herdada por ser final - em java -, sealed - em C# - ou NotInheritable - em VB.Net;
  • Quando temos uma classe que não pode ser herdada por estarmos herdando de uma outra classe qualquer.
padrão decorator

Como usar:

  • Criar uma classe Decorator que implemente IComponent;
  • Adicionar um campo privado do tipo IComponent;
  • Adicionar um construtor que receba um IComponent e o atribua ao campo privado;
  • Implementar IComponent (Operation) de acordo com a sua necessidade;
  • Criar novos métodos (AddedBehavior) e/ou campos (addedState) e/ou propriedades (addedState) de acordo com a sua necessidade.

Exemplo 01:



using System;
using System.Text;


namespace _50minutos_decorator
{
    class Program
    {
        static void Main(string[] args)
        {
            Pessoa pessoa;
            pessoa = new Pessoa();


            Console.WriteLine("usando Pessoa:");
            Console.WriteLine(pessoa.Andar());


            Console.WriteLine();


            PessoaRapida pessoaRapida;
            pessoaRapida = new PessoaRapida(pessoa);


            Console.WriteLine("usando PessoaRapida:");
            Console.WriteLine(pessoaRapida.Andar());
            Console.WriteLine(pessoaRapida.Correr());


            Console.WriteLine();


            PessoaLenta pessoaLenta;
            pessoaLenta = new PessoaLenta(pessoa);


            Console.WriteLine("usando PessoaLenta:");
            Console.WriteLine(pessoaLenta.Andar());


            Console.ReadKey();
        }
    }


    //IComponent
    interface IPessoa 
    {
        //Operation
        String Andar(); 
    }

    //Component
    sealed class Pessoa : IPessoa 
    {
        //Operation
        public String Andar() 
        {
            return "andei";
        }
    }


    //Decorator
    class PessoaRapida : IPessoa 
    {
        //Component : IComponent
        IPessoa p; 


        public PessoaRapida(IPessoa p)
        {
            this.p = p;
        }


        //Operation
        public String Andar() 
        {
            return new StringBuilder(p.Andar())
                .Append(" ")
                .Append("rápido")
                .ToString();
        }


        //AddedBehavior
        public String Correr() 
        {
            return "corri";
        }
    }


    //Decorator
    class PessoaLenta : IPessoa
    {
        //Component : IComponent
        IPessoa p;


        public PessoaLenta(IPessoa p)
        {
            this.p = p;
        }


        //Operation
        public String Andar()
        {
            return new StringBuilder(p.Andar())
                .Append(" ")
                .Append("devagar")
                .ToString();
        }
    }
}


Exemplo 02:



using System;


namespace _50minutos_decorator
{
    class Program
    {
        static void Main(string[] args)
        {
            Sorvete s = new Sorvete();


            Console.WriteLine("Sorvete:");
            Console.WriteLine("{0:c}", s.Preco);


            Console.WriteLine();


            SorveteComCobertura c;
            c = new SorveteComCobertura(s);


            Console.WriteLine("Sorvete com cobertura:");
            Console.WriteLine("{0:c}", c.Preco);


            Console.WriteLine();


            SorveteComBalinha b;
            b = new SorveteComBalinha(s);

            Console.WriteLine("Sorvete com balinha:");
            Console.WriteLine("{0:c}", b.Preco);


            Console.WriteLine();


            SorveteComCobertura cb;
            cb = new SorveteComCobertura(b);


            Console.WriteLine("Sorvete com cobertura E balinha:");
            Console.WriteLine("{0:c}", cb.Preco);


            Console.ReadKey();
        }
    }


    //IComponent
    interface ISorvete
    {
        //State
        double Preco { get; }
    }


    //Component
    sealed class Sorvete : ISorvete
    {
        //State
        public double Preco
        {
            get
            {
                return 1.50;
            }
        }
    }


    //Decorator
    class SorveteComCobertura : ISorvete
    {
        //Component : IComponent
        ISorvete s;


        public SorveteComCobertura(ISorvete s)
        {
            this.s = s;
        }


        //State
        public double Preco
        {
            get
            {
                return this.s.Preco + 0.50;
            }
        }
    }


    //Decorator
    class SorveteComBalinha : ISorvete
    {
        //Component : IComponent
        ISorvete s;


        public SorveteComBalinha(ISorvete s)
        {
            this.s = s;
        }


        //State
        public double Preco
        {
            get
            {
                return this.s.Preco + 0.75;
            }
        }
    }
}