27 de junho de 2011

Design Patterns com Delphi: State - Parte I

Ao longo de sua existência, um objeto em um sistema computacional pode sofrer variações em seu estado interno. Isto é, cada operação realizada com ele ou cada propriedade ajustada altera o valor de variáveis internas (membros), introduzindo mudanças no seu estado. Se o objeto tiver que se comportar de forma diferente de acordo com seu estado interno, a implementação dele tende a se tornar cada vez mais complexa à medida que a quantidade de estados possíveis aumenta, dificultando a manutenção do sistema como um todo.

O Design Pattern comportamental State foi concebido para atender a situações como as descritas no parágrafo anterior, simplificando a manutenção do sistema. Como exemplo do cenário onde o padrão é aplicável, imagine um sistema que controle contas correntes. Dependendo do saldo total, a conta é classificada de uma maneira que determina a disponibilidade de certas operações. Também determina se os serviços disponíveis para a conta são cobrados, a taxa de remuneração que se aplicará ao saldo (se aplicável), taxa juros sobre empréstimos (se aplicável), etc.

A base do conceito para implementarmos esse padrão é a existência de uma interface que torna públicas as operações disponíveis para a classe principal – a conta, no nosso exemplo. O estado interno é mantido por outra classe que tem o conhecimento de como se comportar adequadamente para esse estado específico. Quando a classe principal precisa realizar uma operação, ela delega a responsabilidade para a classe que mantém o estado. Podemos perceber, então, que cada conjunto diferente de comportamentos baseado no estado da classe principal será tratado por uma classe de estado diferente. O resultado desse arranjo é que a classe principal consegue comportar-se da forma planejada apenas trocando a instância interna da classe de estado, o que ocorre de forma transparente para quem usa a classe principal.

Veja no diagrama UML abaixo a relação entre as classes previstas para nosso exemplo:
Diagrama UML para o padrão State

Classes de objetos que podem alternar seu estado de acordo com uma lista previamente conhecida normalmente têm um Diagrama de Estados associado a elas quando modelamos o projeto usando UML. Esse diagrama documenta as mudanças de estado permitidas para o objeto. Com base no saldo existente, a conta do exemplo pode ser classificada como Ouro (melhores taxas de rendimento, menor preço para serviços), Comum (as taxas e preços normais se aplicam) e Diferenciada (o saldo baixo ou negativo leva a menor rendimento, serviços mais caros e proibição de saques e empréstimos).

Formalmente, as classes que participam da solução para o pattern State recebem os seguintes nomes:
Context é a classe que publica as operações que estarão disponíveis para as demais partes do sistema, sendo, por isso, a classe principal da solução. Ela mantém uma referência para a classe que contém o estado atual e o comportamento associado a este estado. No diagrama acima, a classe Context é a TWConta.

State é uma interface que define quais as operações do Context terão comportamento baseado num estado. Ela contém ainda as propriedades relevantes para determinar quando uma troca de estado deve acontecer. Esse papel é executado pela classe TWEstadoConta no diagrama acima. Por ser uma interface, ela normalmente será abstrata, isto é, muitas das funções serão implementadas somente por suas heranças.

Concrete State são as classes que provêem o comportamento adequado para cada estado possível. Elas herdam da interface State, promovendo a implementação necessária para cada operação introduzida por ela. No diagram há 3 classes nessa categoria: TWContaComum, TWContaOuro e TWContaDiferenciada.

Um Client é qualquer parte do sistema que solicite uma operação à classe Context. Esse é o papel da classe TWTelaOperConta no diagrama anterior.

O tipo de hierarquia proposta pelo State é muito semelhante àquela adotada no padrão estrutural Adapter. A diferença é que o Adapter serve para ocultar detalhes de implementação de objetos diferentes que têm a capacidade de executar tarefas similares, adaptando esses objetos a uma interface padronizada. Já o State simplifica a diferenciação de comportamentos dentro de um mesmo objeto. Ou seja, o primeiro foca no aspecto estrutural e envolve várias classes enquanto o segundo foca o comportamento de um único objeto.

No próximo post, mostro uma sugestão de como implementar em Delphi o exemplo usado aqui.

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.