Pular para o conteúdo principal

Application Controller

Descrição​

O Application Controller é um ponto central para tratar a navegação entre telas e o fluxo da aplicação. Ele decide, com base na requisição e no estado atual, qual comando de domínio executar e qual view apresentar em seguida. Assim, o controller de entrada (Page ou Front Controller) fica livre da responsabilidade de conhecer a ordem das telas.

O padrão tem duas partes: uma que mapeia a entrada para a lógica de domínio apropriada e outra que escolhe a view com base no resultado. Essas regras de fluxo, como wizards ou telas dependentes do estado do objeto, ficam em um lugar só, que pode ser configurado, e as views e o domínio não precisam saber da navegação.

Problemas que resolve​

  • Lógica de navegação espalhada entre vários controllers e views.
  • Fluxos dependentes de estado (assistentes, aprovações) difíceis de alterar e testar.
  • Acoplamento entre telas, que precisam conhecer a próxima tela.

Quando usar​

  • Em aplicações com fluxo de telas complexo ou dependente do estado do domínio.
  • Quando as regras de navegação mudam com frequência ou são configuráveis.
  • Quando se quer testar a navegação sem o framework web.

Quando evitar​

  • Quando a navegação é simples e linear, que um mapeamento direto resolve.
  • Quando o framework já traz máquina de fluxos (Spring Web Flow) e basta usá-la.

Trade-offs​

GanhoCusto / Risco
Regras de navegação centralizadasCamada extra de indireção para fluxos simples
Telas independentes umas das outrasPode virar uma máquina de estados difícil de entender
Fluxo testável sem interfaceExige modelar explicitamente estados e transições
Facilita reaproveitar a lógica em outros canaisRisco de absorver regras de domínio indevidamente
  • Acoplamento: reduz o acoplamento entre telas e entre a web e o domínio.
  • Testabilidade: o fluxo é testado com objetos comuns, sem servidor.
  • Estado: fluxos longos exigem guardar o passo atual, tipicamente na sessão.

Diagrama​

O InputController consulta o ApplicationController, que localiza o DomainCommand a executar e escolhe a View seguinte conforme o resultado e o estado.

Exemplo​

Um pedido passa pelas telas de endereço, pagamento e confirmação. O application controller decide a próxima tela pelo estado.

class CheckoutFlow:
TRANSITIONS = {
("address", "ok"): "payment",
("payment", "ok"): "confirmation",
("payment", "declined"): "payment_error",
}

def next_view(self, state: str, result: str) -> str:
return self.TRANSITIONS.get((state, result), "error")

class CheckoutController:
def __init__(self, flow, commands):
self.flow, self.commands = flow, commands

def handle(self, session, action):
result = self.commands[session["step"]].run(action)
session["step"] = self.flow.next_view(session["step"], result)
return session["step"]

Spring Web Flow, os fluxos do JSF e o Windows Workflow são exemplos. Em SPAs, bibliotecas de roteamento e máquinas de estado (XState) fazem esse papel no cliente.

Padrões relacionados​

  • Front Controller — normalmente delega a este padrão a decisão do fluxo.
  • Page Controller — idem, quando a navegação deixa de ser trivial.
  • Model View Controller — o Application Controller refina o papel do controller.
  • Server Session State — guarda o passo atual de fluxos longos.
  • Service Layer — os comandos de domínio costumam ser operações da camada de serviço.
  • Command — comandos de domínio são objetos command.
  • State — fluxos dependentes de estado podem ser modelados assim.

Referência​