Resumo : neste tutorial, você aprenderá sobre o padrão de design Chain of Responsibility e como implementá-lo em C#.
Introdução ao padrão de design de cadeia de responsabilidade C#
O padrão de cadeia de responsabilidade é um padrão comportamental que permite passar uma solicitação por uma cadeia de manipuladores até que um dos manipuladores lide com a solicitação.
Na cadeia de manipuladores, cada manipulador tem uma referência ao próximo manipulador para que possa passar a solicitação para o próximo manipulador até que um dos manipuladores possa tratar a solicitação.
O padrão de cadeia de responsabilidade resolve o problema de determinar qual manipulador em um grupo de manipuladores deve lidar com uma solicitação específica, evitando o acoplamento rígido entre o remetente e o destinatário da solicitação.
Por causa disso, o padrão de cadeia de responsabilidade consegue uma melhor separação de preocupações, reduz a duplicação de código e aumenta a flexibilidade e escalabilidade do seu sistema.
O diagrama UML a seguir ilustra o padrão de design da cadeia de responsabilidade:
Neste diagrama:
Handler
– define uma interface para tratamento de solicitações. OHandler
tem um link para seu sucessor.ConcreteHandler
– é uma classe que implementa aHandler
interface. OConcreteHandler
trata da solicitação pela qual é responsável. SeConcreteHandler
não conseguir atender a solicitação, ele a encaminha ao seu sucessor.Client
– inicia a solicitação para umConcreteHandler
objeto na cadeia.
O Client
passa uma solicitação para uma cadeia de manipuladores até que ConcretteHandler
possa lidar com ela.
Exemplo de padrão de design de cadeia de responsabilidade C#
O programa a seguir ilustra o padrão de cadeia de responsabilidade, que grava mensagens de log em diferentes destinos com base no nível de gravidade da mensagem de log.
namespace ChainOfResponsibilityPattern;
public enum LogLevel
{
Debug,
Info,
Warning,
Error
}
public interface ILogger
{
void Log(string message, LogLevel level);
ILogger? Next
{
get; set;
}
}
public class ConsoleLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Debug || level == LogLevel.Info)
{
Console.WriteLine($"[Console Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
public class FileLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Warning)
{
Console.WriteLine($"[File Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
public class EmailLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Error)
{
Console.WriteLine($"[Email Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
public class Program
{
public static void Main(string[] args)
{
var consoleLogger = new ConsoleLogger();
var fileLogger = new FileLogger();
var emailLogger = new EmailLogger();
consoleLogger.Next = fileLogger;
fileLogger.Next = emailLogger;
consoleLogger.Log("This is a debug message", LogLevel.Debug);
consoleLogger.Log("This is an info message", LogLevel.Info);
consoleLogger.Log("This is a warning message", LogLevel.Warning);
consoleLogger.Log("This is an error message", LogLevel.Error);
}
}
Linguagem de código: C# ( cs )
Saída:
[Console Logger] Debug: This is a debug message
[Console Logger] Info: This is an info message
[File Logger] Warning: This is a warning message
[Email Logger] Error: This is an error message
Linguagem de código: C# ( cs )
Como funciona.
Primeiro, defina a LogLevel
enumeração que contém quatro níveis de log Debug
, Info
, Warning
e Error
:
public enum LogLevel
{
Debug,
Info,
Warning,
Error
}
Linguagem de código: C# ( cs )
Segundo, defina a
interface que possui um ILogger
Log()
método e uma Next
propriedade que serve como seu sucessor na cadeia. A
interface serve como manipulador no padrão:ILogger
public interface ILogger
{
void Log(string message, LogLevel level);
ILogger? Next
{
get; set;
}
}
Linguagem de código: C# ( cs )
Terceiro, defina a ConsoleLogger
classe que implementa a ILogger
interface. Se o nível de log for debug ou info, ele manipulará a mensagem de log exibindo-a no console. Caso contrário, ele encaminha a mensagem de log e o nível de log para seu sucessor:
public class ConsoleLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Debug || level == LogLevel.Info)
{
Console.WriteLine($"[Console Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
Linguagem de código: C# ( cs )
Quarto, defina a FileLogger
classe que implementa a
interface. O ILogger
é semelhante ao, ILogger
ConsoleLogger
exceto que trata apenas da mensagem de log de aviso:
public class FileLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Warning)
{
Console.WriteLine($"[File Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
Linguagem de código: C# ( cs )
Quinto, defina a
classe que implementa a EmailLogger
ILogger
interface. O
lida com a mensagem do log de erros:EmailLogger
public class EmailLogger : ILogger
{
public ILogger? Next
{
get; set;
}
public void Log(string message, LogLevel level)
{
if (level == LogLevel.Error)
{
Console.WriteLine($"[Email Logger] {level}: {message}");
}
else
{
Next?.Log(message, level);
}
}
}
Linguagem de código: C# ( cs )
Por fim, crie três objetos logger, incluindo
, ConsoleLogger
, e FileLogger
EmailLogger
, e defina o próximo manipulador para os objetos
e ConsoleLogger
como FileLogger
e FileLogger
Email
Logger respectivamente. Use
para registrar mensagens com níveis diferentes:ConsoleLogger
public class Program
{
public static void Main(string[] args)
{
var consoleLogger = new ConsoleLogger();
var fileLogger = new FileLogger();
var emailLogger = new EmailLogger();
consoleLogger.Next = fileLogger;
fileLogger.Next = emailLogger;
consoleLogger.Log("This is a debug message", LogLevel.Debug);
consoleLogger.Log("This is an info message", LogLevel.Info);
consoleLogger.Log("This is a warning message", LogLevel.Warning);
consoleLogger.Log("This is an error message", LogLevel.Error);
}
}
Linguagem de código: C# ( cs )
Resumo
- Use o padrão de cadeia de responsabilidade para resolver o problema de determinar qual manipulador deve tratar uma solicitação, evitando ao mesmo tempo um acoplamento rígido entre o remetente e o destinatário da solicitação.