O Design Pattern estrutural Decorator aborda esse tipo de necessidade. Ele foi estabelecido para permitir que se adicione novas funcionalidades (ou responsabilidades) a instâncias de uma classe, de modo que ela pode ser estendida em tempo de execução.
Embora o nome Decorator remeta à algo visual, o uso desse pattern não é restrito ao tratamento de interfaces gráficas. Esta é a aplicação mais comum dele (como no exemplo publicado no Wikipedia) mas pode também ser usado para estender regras de negócio. Por exemplo, numa aplicação para uma locadora onde é permitido alugar ou comprar certos itens (filmes, jogos, etc.), certas funcionalidades (exibir o item) e propriedades (título do item) se aplicam a qualquer tipo de item. No entanto, as ações de "alugar" ou "comprar" um item só são válidas em certos contextos da aplicação, como no momento de registrar o aluguel ou a devolução de um filme alugado.
Para implementar esse conceito, é preciso definir uma interface padrão com as ações comuns a todos os itens. Tanto os itens quanto as "decorações" são heranças dessa interface. A diferença é que as "decorações" são construídas para conter a referência a uma instância da interface e é essa instância quem executará as ações básicas para a decoração. Assim, não importa quantas "decorações" estejam adicionadas (empacotadas) umas nas outras pois o resultado final é sempre um objeto capaz de agir tanto como a interface base quanto como uma das decorações adicionadas. Pode parecer meio confuso à primeira vista mas uma olhada no diagrama UML ajuda a clarear.
Se for necessário acrescentar outras responsabilidades a um item - uma ação para "empréstimo", por exemplo - não é necessário mexer na classe do Item, bastando criar a respectiva decoração e instanciá-la quando for necessário.
A nomenclatura para as classes envolvidas no Decorator é a seguinte :
O Component é quem declara a interface comum a todos os objetos que poderão ter responsabilidades adicionadas dinamicamente, isto é, trata-se de uma classe abstrata que indica o comportamento comum que se deve esperar de todos os integrantes da solução. No diagrama acima, esta interface é representada pela classe TWItem.
É chamado de ConcreteComponent cada um dos itens básicos que implementem a interface estipulada. São tidos como básicos porque não possuem nenhuma das decorações possíveis, embora possam ser atachados a uma ou mais delas. No exemplo, as classes TWFilme e TWJogo são considerados ConcreteComponents.
O Decorator é a classe base para criação de novas decorações (ou responsabilidades). Ela também é uma herança da interface comum (Component) mas com uma diferença : possui internamente um membro que é uma referência a um outro Component e é essa referência quem será responsável por executar as ações para o Decorator e suas heranças. No diagrama acima, o papel de Decorator é exercido pela classe TWItemDecorator.
Cada nova classe ConcreteDecorator permite adicionar uma ou mais ações à classe Component. Atachar uma dessas classes a um ConcreteComponent estende suas funcionalidades já que o ConcreteComponent passa a enxergar as ações disponibilizadas pelo Decorator em questão. É permitido aninhar diversos Decorators, o que na prática adiciona várias funcionalidades ao ConcreteComponent e amplia o escopo onde ele pode ser usado dentro das necessidades do programa modelado. As classes TWItemAlugel e TWItemVenda no diagrama anterior são exemplos de ConcreteDecorator; adicioná-las a um filme ou jogo proporcionará a possibilidade de alugá-los ou vendê-los, respectivamente. Tudo isso em tempo de execução.
É chamado de ConcreteComponent cada um dos itens básicos que implementem a interface estipulada. São tidos como básicos porque não possuem nenhuma das decorações possíveis, embora possam ser atachados a uma ou mais delas. No exemplo, as classes TWFilme e TWJogo são considerados ConcreteComponents.
O Decorator é a classe base para criação de novas decorações (ou responsabilidades). Ela também é uma herança da interface comum (Component) mas com uma diferença : possui internamente um membro que é uma referência a um outro Component e é essa referência quem será responsável por executar as ações para o Decorator e suas heranças. No diagrama acima, o papel de Decorator é exercido pela classe TWItemDecorator.
Cada nova classe ConcreteDecorator permite adicionar uma ou mais ações à classe Component. Atachar uma dessas classes a um ConcreteComponent estende suas funcionalidades já que o ConcreteComponent passa a enxergar as ações disponibilizadas pelo Decorator em questão. É permitido aninhar diversos Decorators, o que na prática adiciona várias funcionalidades ao ConcreteComponent e amplia o escopo onde ele pode ser usado dentro das necessidades do programa modelado. As classes TWItemAlugel e TWItemVenda no diagrama anterior são exemplos de ConcreteDecorator; adicioná-las a um filme ou jogo proporcionará a possibilidade de alugá-los ou vendê-los, respectivamente. Tudo isso em tempo de execução.
Mostro em outro post como mapear essas relações usando Delphi e também como fazer as chamadas para obter o resultado desejado.
Nenhum comentário :
Postar um comentário
OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.
Observação: somente um membro deste blog pode postar um comentário.