Processa ou Passa? : Padrão de Design Chain of Responsibility
O padrão de design Chain of Responsibility, traduzido como “Cadeia de Responsabilidade”, é um padrão comportamental que permite passar solicitações por uma cadeia de manipuladores. Cada manipulador decide se processa a solicitação ou a passa adiante para o próximo manipulador na cadeia. Esse padrão dá uma abordagem flexível para lidar com solicitações, permite que múltiplos objetos possam ter a oportunidade de processar um pedido sem um acoplamento forte entre eles.
Na implementação do padrão Chain of Responsibility, cada manipulador contém uma referência para o próximo objeto na cadeia. Quando uma solicitação é recebida, o primeiro manipulador decide se pode ou não lidar com ela. Se puder, a solicitação é processada , caso contrário, é passada para o próximo manipulador na cadeia. Esse processo continua até que a solicitação seja manipulada ou até que todos os manipuladores tenham sido percorridos.
Vantagens da Chain of Responsibility:
- Desacoplamento: Os remetentes não precisam saber quais objetos específicos na cadeia irão manipular o pedido. Isso ajuda a reduzir o acoplamento entre componentes.
- Flexibilidade: Adicionar ou remover nós na cadeia é relativamente simples, o que proporciona flexibilidade no tratamento de pedidos.
- Manutenção: Facilita a manutenção, pois cada nó é responsável por uma tarefa específica.
Desvantagens da Chain of Responsibility:
- Risco de não tratamento: Se não houver um tratamento definido para um pedido na cadeia, ele pode chegar ao final sem ser manipulado, levando a problemas de execução.
Exemplo de Implementação com Dart
Imagina um aplicativo que processa diferentes tipos de autenticação. Utilizando o padrão Chain of Responsibility, podemos criar uma cadeia de manipuladores para processar esses tipos.
// Classe base para os handlers da autenticação
abstract class ManipuladorAutenticacao {
ManipuladorAutenticacao? _proximoManipulador;
set proximo(ManipuladorAutenticacao manipulador) {
_proximoManipulador = manipulador;
}
void autenticar(String usuario, String senha);
}
// Manipulador para autenticação por email e senha
class ManipuladorEmailSenha extends ManipuladorAutenticacao {
@override
void autenticar(String usuario, String senha) {
// Lógica para autenticar por email e senha
if (usuario == 'utilizador@exemplo.com' && senha == 'senha123') {
print('Autenticação por email e senha bem-sucedida.');
} else if (_proximoManipulador != null) {
_proximoManipulador!.autenticar(usuario, senha);
} else {
print('Não foi possível autenticar por email e senha.');
}
}
}
// Manipulador para autenticação por autenticação biométrica
class ManipuladorBiometrico extends ManipuladorAutenticacao {
@override
void autenticar(String usuario, String senha) {
// Simulação de autenticação biométrica bem-sucedida
if (usuario == 'utilizador_biometrico' && senha.isEmpty) {
print('Autenticação biométrica bem-sucedida.');
} else if (_proximoManipulador != null) {
_proximoManipulador!.autenticar(usuario, senha);
} else {
print('Não foi possível autenticar por biometria.');
}
}
}
// Manipulador para autenticação de fallback (último recurso)
class ManipuladorFallback extends ManipuladorAutenticacao {
@override
void autenticar(String usuario, String senha) {
// Autenticação de fallback (último recurso)
print('Autenticação de fallback ativada. Autenticação não suportada.');
}
}
void main() {
// Configurando a cadeia de responsabilidade para autenticação
final manipuladorEmailSenha = ManipuladorEmailSenha();
final manipuladorBiometrico = ManipuladorBiometrico();
final manipuladorFallback = ManipuladorFallback();
manipuladorEmailSenha.proximo = manipuladorBiometrico;
manipuladorBiometrico.proximo = manipuladorFallback;
// Simulando tentativas de autenticação
manipuladorEmailSenha.autenticar('utilizador@exemplo.com', 'senha123');
manipuladorBiometrico.autenticar('utilizador_biometrico', '');
manipuladorEmailSenha.autenticar('utilizador_desconhecido', '123456');
}
Neste exemplo, temos três handlers de autenticação: ManipuladorEmailSenha para autenticação por email e senha, ManipuladorBiometrico para autenticação biométrica e ManipuladorFallback como um último recurso caso nenhum método de autenticação anterior seja bem sucedido.
Se um método de autenticação falhar, o próximo na cadeia é chamado, e assim por diante, até que um método autentique com sucesso ou a cadeia termine.
Este exemplo demonstra como o padrão Chain of Responsibility pode ser aplicado para lidar com métodos de autenticação diferentes, permitindo adicionar ou remover métodos de autenticação na cadeia de forma flexível sem modificar o código existente.
Então quando o teu projecto precisar decidir qual tratamento dar a um pense nesse design pattern.