Princípio C# aberto-fechado

Resumo : neste tutorial, você aprenderá sobre o princípio aberto-fechado do C# e como usá-lo para escrever código aberto para extensão e fechado para modificação.

Introdução ao princípio C# aberto-fechado

O Princípio Aberto-Fechado (OCP) é o segundo princípio dos princípios SOLID de design orientado a objetos:

O princípio Aberto-fechado afirma que as entidades de software ( classes , métodos, funções, etc.) devem ser abertas para extensão, mas fechadas para modificação.

Em termos simples, você deve projetar uma classe ou método de forma que possa estender seu comportamento sem modificar diretamente o código-fonte existente.

Exemplo de princípio aberto-fechado em C#

O programa a seguir ilustra uma violação do princípio aberto-fechado:

public class Invoice
{
    public int InvoiceNo {  get; set; }
    public DateOnly IssuedDate {  get; set; }
    public string? Customer { get; set; }
    public decimal Amount {  get; set; }
    public string? Description { get; set;}
}

class InvoiceRepository
{
    public void SaveFile(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a file.");
    }
    public void SaveDB(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a database.");
    }
}

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice to a storage
        var invoiceRepository = new InvoiceRepository();
        invoiceRepository.SaveFile(invoice);

    }
}Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina uma Invoiceclasse que tenha propriedades InvoiceNo, IssuedDate, Customer, Amounte Description:

public class Invoice
{
    public int InvoiceNo {  get; set; }
    public DateOnly IssuedDate {  get; set; }
    public string? Customer { get; set; }
    public decimal Amount {  get; set; }
    public string? Description { get; set;}
}Linguagem de código:  C#  ( cs )

Segundo, defina uma InvoiceRepositoryclasse que tenha dois métodos SaveFile()e SaveDb(). Esses métodos salvam uma fatura em um arquivo e em um banco de dados, respectivamente:

class InvoiceRepository
{
    public void SaveFile(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a file.");
    }
    public void SaveDB(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a database.");
    }
}Linguagem de código:  C#  ( cs )

Para simplificar, esses métodos enviam uma mensagem para o console em vez de salvar uma fatura em um arquivo e banco de dados.

Terceiro, crie uma nova fatura e chame os métodos SaveFile()e SaveDB()para salvar a fatura em um arquivo e banco de dados no Main()método da Programclasse:

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice to a storage
        var invoiceRepository = new InvoiceRepository();
        invoiceRepository.SaveFile(invoice);

    }
}Linguagem de código:  C#  ( cs )

Suponha que você precise salvar uma fatura em um JSONarquivo e, em seguida, modifique a InvoiceRepositoryclasse adicionando mais um método à InvoiceRepositoryclasse como este:

class InvoiceRepository
{
    public void SaveFile(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a file.");
    }
    public void SaveDB(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a database.");
    }

    public void SaveJSON(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a JSON file.");
    }
}Linguagem de código:  C#  ( cs )

Isso viola o princípio aberto-fechado porque adicionar uma nova função requer a modificação da classe existente.

Refatorando o programa para seguir o princípio aberto-fechado

Para que o programa esteja em conformidade com o princípio Aberto-fechado, é necessário redesenhar a InvoiceRepositoryclasse para que, quando quiser salvar uma fatura em um armazenamento diferente, não seja necessário modificá-la.

Primeiro, defina uma IInvoiceRepositoryinterface que possua um Save()método que salve uma fatura no armazenamento:

interface IInvoiceRepository
{
    void Save(Invoice invoice);
}Linguagem de código:  C#  ( cs )

Segundo, defina três classes que implementam a IInvoiceRepositoryinterface. Essas classes são responsáveis ​​por salvar uma fatura em vários armazenamentos, incluindo arquivos de texto, bancos de dados e arquivos JSON:

class FileInvoiceRepository : IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a file.");
    }
}

class DBInvoiceRepository : IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into the database.");
    }
}

class JSONInvoiceRepository: IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into the database.");
    }
}Linguagem de código:  C#  ( cs )

Posteriormente, se quiser salvar uma fatura em um armazenamento diferente, você poderá criar uma nova classe que implemente a fatura IInvoiceRepositorysem modificar as classes e interfaces existentes.

Terceiro, crie uma fatura e salve-a em um arquivo de texto, um arquivo JSON e um banco de dados chamando os Save()métodos:

class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice a file
        IInvoiceRepository repo = new FileInvoiceRepository();
        repo.Save(invoice);

        // save the invoice to the DB
        repo = new DBInvoiceRepository();
        repo.Save(invoice);

        // save the invoice to the JSON file
        repo = new JSONInvoiceRepository();
        repo.Save(invoice);

    }
}Linguagem de código:  C#  ( cs )

Junte tudo.


public class Invoice
{
    public int InvoiceNo {  get; set; }
    public DateOnly IssuedDate {  get; set; }
    public string? Customer { get; set; }
    public decimal Amount {  get; set; }
    public string? Description { get; set;}
}


interface IInvoiceRepository
{
    void Save(Invoice invoice);
}

class FileInvoiceRepository : IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into a file.");
    }
}

class DBInvoiceRepository : IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into the database.");
    }
}

class JSONInvoiceRepository: IInvoiceRepository
{
    public void Save(Invoice invoice)
    {
        Console.WriteLine($"Saved the invoice #{invoice.InvoiceNo} into the database.");
    }
}


class Program
{
    public static void Main(string[] args)
    {
        // create a new invoice
        var invoice = new Invoice
        {
            InvoiceNo = 1,
            Customer = "John Doe",
            IssuedDate = new DateOnly(2023, 4, 1),
            Description = "Website Design",
            Amount = 1000
        };

        // save the invoice a file
        IInvoiceRepository repo = new FileInvoiceRepository();
        repo.Save(invoice);

        // save the invoice to the DB
        repo = new DBInvoiceRepository();
        repo.Save(invoice);

        // save the invoice to the JSON file
        repo = new JSONInvoiceRepository();
        repo.Save(invoice);

    }
}Linguagem de código:  C#  ( cs )

Benefícios do Princípio Aberto-Fechado

O princípio aberto-fechado traz os seguintes benefícios:

  • Reutilização de código: quando você projeta uma classe para ser aberta para extensão, fica mais fácil reutilizar esse código em outras partes do sistema. Ao criar código reutilizável, você pode economizar tempo e esforço no longo prazo. Além disso, fica mais fácil adicionar novas funcionalidades ao sistema sem impactar o código existente
  • Complexidade de código reduzida: ao criar classes fechadas para modificação, você pode reduzir a complexidade da base de código. Conseqüentemente, você pode facilitar a manutenção e extensão do sistema quando desejar adicionar novos recursos ou fazer alterações.
  • Maior flexibilidade: O princípio aberto-fechado promove flexibilidade no sistema de software que permite adicionar novas funcionalidades ao sistema com facilidade e confiança, sem modificar o código existente. Isso torna mais fácil responder rapidamente às mudanças nos requisitos.

Resumo

  • O princípio aberto-fechado afirma que classes, métodos, etc., devem ser abertos para extensão, mas fechados para modificação.
  • Aproveite o princípio aberto-fechado para projetar software que seja mais modular, flexível e de fácil manutenção.

Deixe um comentário

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