Padrão de design de cadeia de responsabilidade C#

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:

Padrão de design de cadeia de responsabilidade C#

Neste diagrama:

  • Handler– define uma interface para tratamento de solicitações. O Handlertem um link para seu sucessor.
  • ConcreteHandler– é uma classe que implementa a Handlerinterface. O ConcreteHandlertrata da solicitação pela qual é responsável. Se ConcreteHandlernão conseguir atender a solicitação, ele a encaminha ao seu sucessor.
  • Client– inicia a solicitação para um ConcreteHandlerobjeto na cadeia.

O Clientpassa uma solicitação para uma cadeia de manipuladores até que ConcretteHandlerpossa 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 messageLinguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina a LogLevelenumeração que contém quatro níveis de log Debug, Info, Warninge Error:

public enum LogLevel
{
    Debug,
    Info,
    Warning,
    Error
}Linguagem de código:  C#  ( cs )

Segundo, defina a ILoggerinterface que possui um Log()método e uma Nextpropriedade que serve como seu sucessor na cadeia. A ILoggerinterface serve como manipulador no padrão:

public interface ILogger
{
    void Log(string message, LogLevel level);
    ILogger? Next
    {
        get; set;
    }
}Linguagem de código:  C#  ( cs )

Terceiro, defina a ConsoleLoggerclasse que implementa a ILoggerinterface. 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 FileLoggerclasse que implementa a ILoggerinterface. O ILoggeré semelhante ao, ConsoleLoggerexceto 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 EmailLoggerclasse que implementa a ILoggerinterface. O EmailLoggerlida com a mensagem do log de erros:

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, FileLogger, e EmailLogger, e defina o próximo manipulador para os objetos ConsoleLoggere FileLoggercomo FileLoggere EmailLogger respectivamente. Use ConsoleLoggerpara registrar mensagens com níveis diferentes:

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.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *