Padrão State em Python
Published: 2020-12-13 23:38:40

O Padrão State é um **padrão de projeto comportamental**, implementa uma solução que altera o comportamento de um objeto de acordo com o seu estado interno. Está diretamente relacionado ao conceito da Máquina de Estado Finito.

Este padrão recomenda que novas classes sejam criadas para todos os estados possíveis de um objeto, extraindo todos os comportamentos específicos de estados para dentro dessas classes. Desta forma o objeto principal não irá implementar todos os comportamentos por conta própria, apenas irá armazenar uma referência ao objeto que representa seu estado atual, todo o trabalho relacionado ao estado será delegado para este objeto.

###Exemplo do Padrão State em Python

#### Classe Context
```python
class Context:

    _state = None

    def __init__(self, state: State) -> None:
        self.transition_to(state)

    def transition_to(self, state: State):
        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()
```
A classe *Context* é a representação do contexto do objeto, ela armazena uma referência a um dos objetos de estado, todos os trabalhos específicos do estado são delegados a este objeto referenciado. Essa comunicação se dá através da interface do estado. A função *transition_to* implementa um setter que recebe um novo objeto de estado e executa a transição.

####Classe State

```python
class State(ABC):

    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context) -> None:
        self._context = context

    @abstractmethod
    def handle1(self) -> None:
        pass

    @abstractmethod
    def handle2(self) -> None:
        pass
```
A classe *State* é a classe que declara os métodos que cada estado do objeto pode ter, esta possui métodos que serão especificados em cada instância de estado, desta forma devem ser declarados de forma que faça sentido para todos os estados do objeto.

####Classe ConcreteStateA
```python
class ConcreteStateA(State):
    def handle1(self) -> None:
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")
        self.context.transition_to(ConcreteStateB())

    def handle2(self) -> None:
        print("ConcreteStateA handles request2.")


class ConcreteStateB(State):
    def handle1(self) -> None:
        print("ConcreteStateB handles request1.")

    def handle2(self) -> None:
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")
        self.context.transition_to(ConcreteStateA())
``` 
A classe *ConcreteStateA* representa uma instância de estado, implementando seus métodos específicos. Cada método lida com a requisição da sua maneira particular podendo fazer a transição entre outros estados na sua execução.

O uso do Padrão State é indicado quando um objeto se comporta de maneira diferente dependendo do seu estado, quando o número de estados é grande, quando uma classe possui grandes blocos de condicionais que determinam seu comportamento e quando existe muito código duplicado entre os diferentes estados de um objeto.

A implementação em Python não tem nenhuma particularidade em relação a implementação em Java.

***
**Referências**
[Padrões de Projeto](https://diogomoreira.gitbook.io/padroes-de-projeto/) (Diogo Moreira, 2020)
[Mergulho nos Padrões de Projeto - v2020-1.14](https://refactoring.guru/pt-br/design-patterns/book) (Alexander Shvets, 2020)
*Os códigos usados como exemplo foram retirados do livro Mergulho nos Padrões de Projeto.*