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:
- Princípio de Responsabilidade Única (SRP)
- Princípio Aberto-Fechado (OCP)
- Princípio de Substituição de Liskov (LSP)
- Princípio de segregação de interface (ISP)
- Princípio de Inversão de Dependência (DIP)
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 Invoice
classe que tenha propriedades InvoiceNo
, IssuedDate
, Customer
, Amount
e 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 InvoiceRepository
classe 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 Program
classe:
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 JSON
arquivo e, em seguida, modifique a
classe adicionando mais um método à InvoiceRepository
classe como este:InvoiceRepository
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 InvoiceRepository
classe para que, quando quiser salvar uma fatura em um armazenamento diferente, não seja necessário modificá-la.
Primeiro, defina uma IInvoiceRepository
interface 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 IInvoiceRepository
interface. 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 IInvoiceRepository
sem 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.