.NET - O padrão de projeto Decorator
O padrão de projeto Decorator é um padrão estrutural que permite agregar dinamicamente responsabilidades adicionais a um objeto fornecendo assim uma alternativa flexível à utilização da herança como modo de estender funcionalidades. |
Em uma definição mais formal de acordo com Gamma um padrão Decorator permite:
Dinamicamente, agregar responsabilidades adicionais a um objeto. Os decoradores fornecem uma alternativa flexível ao uso de subclasses para extensão de funcionalidades. (GAMMA et al., 2000:170).
Nota: Padrões de projeto estruturais são padrões que lidam com as estruturas do projeto, facilitando a comunicação entre suas entidades. Dessa forma eles tratam a maneira como objetos e classes estão dispostos em um projeto a fim de formar estruturas mais complexas.
De forma mais simples podemos dizer que o padrão Decorator permite estender (decorar) dinamicamente as características de uma classe usando a composição.
O diagrama de classes para o padrão Decorator usando a notação UML é mostrado na figura abaixo:
Classes/Objetos
participantes do padrão:
|
Vantagens em usar o padrão Decorator:
Quando usar o padrão Decorator ?
Implementando o padrão de projeto Decorator
Este exemplo foi baseado no livro Use a Cabeça (head first) Padrões de Projeto, FREEMAN (2007:81-96).
Para implementar o padrão Decorator eu vou usar o seguinte cenário: Carros e seus opcionais. (poderiamos ter usado Pizzas, Lanches, Bebidas e seus respectivos acessários.)
Imagem um carro , pode ser de qualquer marca ou modelo, e , no nosso exemplo será uma Ferrari.
Geralmente um carro é oferecido na configuração padrão que pode ser acrescida de opcionais que tem um valor que deve ser somando ao valor do carro.
Assim uma Ferrari é vendida com uma configuração padrão e no nosso exemplo vamos decorá-la com dois opcionais : Motor Turbo e Bancos de Couro.
Neste cenário iremos ter as seguintes classes:
A seguir temos o diagrama de classes:
|
Vamos agora criar as classes e verificar o seu funcionamento.
Eu vou usar o Visual C# 2010 Express Edition e criar uma aplicação Console chamada PadroProjetoDecorator;
No menu Procjet clique em Add Class e informe o nome Carro.cs e a seguir digite o código da classe Carro conforme abaixo:
namespace PadraoProjetoDecorator { public abstract class Carro { private double _preco = -1; private string _descricao = "Carro Abstrato."; public virtual double Preco { get { return _preco; } } public virtual string Descricao { get { return _descricao; } } } } |
A seguir vamos declarar a classe Decorator chamada DecoratorCarro.cs conforme o código a seguir:
namespace PadraoProjetoDecorator { public abstract class DecoratorCarro : Carro { double _preco = -1; string _descricao = "Decorador Abstrato de Carro"; public override double Preco { get { return _preco; } } public override string Descricao { get { return _descricao; } } } } |
Agora vamos criar a classe FerrariSpider que representa um Ferrari padrão:
namespace PadraoProjetoDecorator { class FerrariSpider : Carro { double _preco = 255000.99; string _descricao = "Ferrari Spider, "; public override double Preco { get { return _preco; } } public override string Descricao { get { return _descricao; } } } } |
Agora vamos criar as classes dos opcionais que serão usadas para decorar o carro padrão. Vamos começar com a classe Ferrari_Turbo conforme o código abaixo:
namespace PadraoProjetoDecorator { class Ferrari_Turbo : DecoratorCarro { double _preco = 9500.50; string _descricao = "Turbo, "; Carro _carro; public Ferrari_Turbo(Carro carro) { _carro = carro; } public override double Preco { get { return _carro.Preco + _preco; } } public override string Descricao { get { return _carro.Descricao + _descricao; } } } } |
Da mesma forma vamos criar a classe Ferrari_Couro conforme abaixo:
namespace PadraoProjetoDecorator { public class Ferrari_Couro : DecoratorCarro { double _preco = 4250.25; string _descricao = "Banco de Couros, "; Carro _carro; public Ferrari_Couro(Carro carro) { _carro = carro; } public override double Preco { get { return _carro.Preco + _preco; } } public override string Descricao { get { return _carro.Descricao + _descricao; } } } } |
Finalmente para testar o padrão Decorator vamos incluir o código abaixo no arquivo Program.cs:
using System; namespace PadraoProjetoDecorator { class Program { static void Main(string[] args) { //criar um carro Console.WriteLine(" --------------Ferrari Padrão-----------------------"); Carro carro = new FerrariSpider(); Console.WriteLine("Descricao --> " + carro.Descricao.TrimEnd(' ', ',')); Console.WriteLine("Preco -->" + carro.Preco.ToString()); Console.ReadLine(); Console.WriteLine(" --------------Ferrari Decorada---------------------"); //decora o carro com banco de couro carro = new Ferrari_Couro(carro); //decora o carro com motor turbo carro = new Ferrari_Turbo(carro); Console.WriteLine("Descricao --> "+ carro.Descricao.TrimEnd(' ', ',')); Console.WriteLine("Preco -->" + carro.Preco.ToString()); Console.ReadLine(); } } } |
Abaixo vemos o resultado da execução do projeto:
Criando os carros e seus opcionais separados temos que as classes se tornam mais reutilizáveis.
Qualquer opcional pode ser usado para decorar qualquer carro, desde que o carro específico implemente um tipo Carro e o opcional especifico implemente o tipo DecoratorCarro.
Como cada carro e cada opcional são encapsulados em suas próprias classes, não há perigo de quebrar a implementação em outros carros ou opcionais quando modificações de um carro específico ou opcional for necessário.
Pela mesma razão, podemos adicionar novos carros e opcionais sem medo de quebrar implementações existentes. Opcionais já definidos podem ser facilmente reutilizados para carros novos que são criados.
Por outro lado, se novos opcionais são definidos para carros existentes, não há necessidade de modificar o código para o próprio carro. Decorar um carro com opcionais desta maneira é muito fácil, e cria um código muito limpo, sustentável e legível. Tudo que você tem que fazer é criar uma instância do carro que você quer decorar e passar o exemplo para o construtor de qualquer opcional com o qual você quer decorar o carro.
Pegue a solução completa aqui: PadraoProjetoDecorator1.zip
João 4:22
Vós adorais o que não conheceis; nós adoramos o que conhecemos; porque a salvação vem dos judeus.Referências: