AYUDA .NET

Principios sólidos C# (Cómo funciona para desarrolladores)

Publicado en 12 de diciembre, 2023
Compartir:

Los principios SOLID son cinco principios de diseño que, si se siguen, pueden crear entidades de software robustas y mantenibles. Robert C. Martin introdujo estos principios, que se convirtieron en la piedra angular del diseño orientado a objetos. En C#, un popular lenguaje de programación orientado a objetos desarrollado por Microsoft, comprender y aplicar los principios SOLID puede mejorar considerablemente la calidad del código.

En este artículo, haremos una revisión detallada de Principios sólidos en C# y sus usos, y también veremos cómo se pueden utilizar para escribir estructuras de código reutilizables mediante la creación de documentos PDF utilizando la biblioteca PDF de C#. IronPDF.

1. Los Cinco Principios SOLID en C#

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 1

1.1. Principio de Responsabilidad Única (PRU)

El principio de responsabilidad única establece que una clase sólo debe tener una razón para cambiar, lo que significa que sólo debe tener una responsabilidad. En C#, este principio anima a los desarrolladores a crear clases centradas en una tarea específica. Por ejemplo, una clase responsable de gestionar operaciones con archivos no debería serlo también de las conexiones a bases de datos.

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 2

1.2. Principio Abierto/Cerrado (PCA)

El principio abierto/cerrado sugiere que una clase debe estar abierta a la ampliación pero cerrada a la modificación, lo que permite ampliar el comportamiento de un módulo sin modificar su código fuente. En C#, esto se consigue a menudo mediante interfaces y clases abstractas, que permiten crear nuevas clases que se adhieren a los contratos existentes.

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 3

1.3. Principio de sustitución de Liskov (PSL)

La Sustitución de Liskov hace hincapié en que los objetos de una superclase sean sustituibles por objetos de una subclase sin que ello afecte a la corrección del programa. En C#, este principio fomenta el polimorfismo para garantizar que las clases derivadas puedan utilizar sus clases base indistintamente.

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 4

1.4. Principio de segregación de interfaces (ISP)

El principio de segregación de interfaces aboga por utilizar interfaces pequeñas y específicas en lugar de grandes y generales. En C#, este principio desaconseja la creación de interfaces "gordas" que obliguen a las clases implementadoras a proporcionar funcionalidades que no necesitan. En su lugar, fomenta el uso de múltiples pequeñas interfaces adaptadas a necesidades específicas.

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 5

1.5. Principio de inversión de la dependencia (DIP)

La inversión de dependencia promueve la idea de que los módulos de alto nivel no deben depender de los módulos de bajo nivel, sino que ambos deben depender de la clase de abstracción. En C#, esto suele implicar el uso de la inyección de dependencias para invertir el flujo de control tradicional, lo que permite un código más flexible y comprobable.

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 6

2. Usos de los principios de diseño SOLID

Los principios SOLID proporcionan una hoja de ruta para diseñar un código limpio y fácil de mantener. No hay que seguirlas ciegamente en todas las situaciones, sino aplicarlas con criterio en función del contexto de una aplicación determinada.

2.1. Principio de Responsabilidad Única (SRP)

El Principio de Responsabilidad Única puede ser beneficioso a la hora de diseñar clases en una aplicación C#. Garantizar que cada clase tenga una única responsabilidad hace que el código sea más modular y fácil de entender. Esta modularidad es beneficiosa para el mantenimiento y simplifica la adición de nuevas funciones o la corrección de errores sin afectar a toda la base de código.

2.2. Principio Abierto/Cerrado (PCA)

El principio de abierto/cerrado se aplica cuando hay que ampliar el código pero no modificarlo. Mediante interfaces y clases abstractas, los desarrolladores en C# pueden crear sistemas adaptables sin cambiar el código existente.

2.3. Principio de sustitución de Liskov (LSP)

El Principio de Sustitución de Liskov garantiza que las clases derivadas puedan sustituirse sin problemas por sus clases base, promoviendo una base de código más flexible y escalable. Aplicar el principio de sustitución de Liskov es especialmente importante cuando el polimorfismo es crucial.

2.4. Principio de segregación de interfaces (ISP)

El principio de segregación de interfaces fomenta la creación de interfaces pequeñas y específicas, adaptadas a las necesidades de las clases que las implementan. Este enfoque evita la imposición de métodos innecesarios a las clases, promoviendo un diseño más eficiente y mantenible.

2.5. Principio de inversión de la dependencia (DIP)

El principio de inversión de dependencias, a través de la inyección de dependencias, facilita la creación de componentes poco acoplados en una aplicación C#. La aplicación de este principio reduce la complejidad global del código y mejora su comprobabilidad.

2.6. Ejemplo

using System;
public abstract class Shape
{
    public abstract double Area();
}
class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area() => Math.PI * Math.Pow(Radius, 2);
}
class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area() => Width * Height;
}
class AreaCalculator
{
    public double CalculateArea(Shape shape) => shape.Area();
}
interface ILogger 
{
    void Log(string message); // interface segregation principle d
}
class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"Log: {message}");
}
class FileLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"File Log: {message}");
}
class UserService
{
    private readonly ILogger logger;
    public UserService(ILogger logger) => this.logger = logger;
    public void CreateUser()
    {
        logger.Log("User created successfully");
    }
}
class EmailService
{
    private readonly ILogger logger;
    public EmailService(ILogger logger) => this.logger = logger;
    public void SendEmail()
    {
        logger.Log("Email sent successfully");
    }
}
using System;
public abstract class Shape
{
    public abstract double Area();
}
class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area() => Math.PI * Math.Pow(Radius, 2);
}
class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area() => Width * Height;
}
class AreaCalculator
{
    public double CalculateArea(Shape shape) => shape.Area();
}
interface ILogger 
{
    void Log(string message); // interface segregation principle d
}
class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"Log: {message}");
}
class FileLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"File Log: {message}");
}
class UserService
{
    private readonly ILogger logger;
    public UserService(ILogger logger) => this.logger = logger;
    public void CreateUser()
    {
        logger.Log("User created successfully");
    }
}
class EmailService
{
    private readonly ILogger logger;
    public EmailService(ILogger logger) => this.logger = logger;
    public void SendEmail()
    {
        logger.Log("Email sent successfully");
    }
}
Imports System
Public MustInherit Class Shape
	Public MustOverride Function Area() As Double
End Class
Friend Class Circle
	Inherits Shape

	Public Property Radius() As Double
	Public Overrides Function Area() As Double
		Return Math.PI * Math.Pow(Radius, 2)
	End Function
End Class
Friend Class Rectangle
	Inherits Shape

	Public Property Width() As Double
	Public Property Height() As Double
	Public Overrides Function Area() As Double
		Return Width * Height
	End Function
End Class
Friend Class AreaCalculator
	Public Function CalculateArea(ByVal shape As Shape) As Double
		Return shape.Area()
	End Function
End Class
Friend Interface ILogger
	Sub Log(ByVal message As String) ' interface segregation principle d
End Interface
Friend Class ConsoleLogger
	Implements ILogger

	Public Sub Log(ByVal message As String) Implements ILogger.Log
		Console.WriteLine($"Log: {message}")
	End Sub
End Class
Friend Class FileLogger
	Implements ILogger

	Public Sub Log(ByVal message As String) Implements ILogger.Log
		Console.WriteLine($"File Log: {message}")
	End Sub
End Class
Friend Class UserService
	Private ReadOnly logger As ILogger
	Public Sub New(ByVal logger As ILogger)
		Me.logger = logger
	End Sub
	Public Sub CreateUser()
		logger.Log("User created successfully")
	End Sub
End Class
Friend Class EmailService
	Private ReadOnly logger As ILogger
	Public Sub New(ByVal logger As ILogger)
		Me.logger = logger
	End Sub
	Public Sub SendEmail()
		logger.Log("Email sent successfully")
	End Sub
End Class
VB   C#

En este fragmento de código, una clara aplicación de la programación orientada a objetos (OOP) principios, en concreto los principios SOLID, es evidente. La clase Shape sirve como clase base abstracta, definiendo el concepto común de formas y declarando el método abstracto Area(). El término "clase hija o derivada" se refiere a las clases Círculo y Rectángulo, ya que heredan de la clase padre común. Tanto Círculo como Rectángulo actúan como clases derivadas, ampliando la funcionalidad de la clase base abstracta y proporcionando implementaciones concretas de Área() método. Además, el código ejemplifica los principios de SOLID, como el principio de responsabilidad única (SRP)donde cada clase tiene una responsabilidad distinta, y el Principio de Inversión de Dependencia (DIP)como demuestra el uso de la interfaz ILogger, que fomenta la flexibilidad y la facilidad de mantenimiento.

3. Aplicación del principio SOLID en IronPDF

Ahora que hemos explorado los principios SOLID en teoría, vamos a profundizar en su aplicación práctica en C# utilizando IronPDF, una popular biblioteca para trabajar con archivos PDF. IronPDF permite a los desarrolladores crear, manipular y procesar documentos PDF sin problemas en C#. Al integrar los principios SOLID, podemos garantizar que nuestro código siga siendo modular, extensible y mantenible.

Considere el principio de responsabilidad única. Cuando se trabaja con IronPDF, es beneficioso tener clases que manejen aspectos específicos de la generación o manipulación de PDF. Por ejemplo, una clase podría crear documentos PDF, mientras que otra se centra en añadir y dar formato al contenido.

El Principio Abierto/Cerrado nos anima a diseñar nuestras clases relacionadas con PDF teniendo en cuenta la extensión. En lugar de modificar las clases existentes para adaptarlas a las nuevas funciones, podemos crear clases que amplíen o implementen las interfaces existentes. De este modo, cumplimos el principio sin comprometer la funcionalidad existente.

El principio de sustitución de Liskov entra en juego cuando se trata de distintos tipos de elementos PDF. Ya se trate de texto, imágenes o anotaciones, el diseño de clases que se adhieran a una interfaz común permite una sustitución sin problemas y mejora la flexibilidad de nuestro código de generación de PDF. El principio de segregación de interfaces es esencial a la hora de definir contratos para las clases que interactúan con IronPDF. Al crear pequeñas interfaces específicas adaptadas a las necesidades de los distintos componentes, evitamos dependencias innecesarias y garantizamos que las clases sólo implementen los métodos que necesitan.

Por último, la aplicación del Principio de Inversión de Dependencias puede mejorar la comprobabilidad y mantenibilidad de nuestro código. Al inyectar dependencias en lugar de codificarlas, creamos un sistema más flexible que es más fácil de actualizar y ampliar.

Ilustremos estos conceptos con un sencillo ejemplo de código utilizando IronPDF:

using IronPdf;
using System;
// Interface for PDF creation
public interface IPdfCreator
{
    void CreatePdf(string filePath,string content);
}
// Concrete implementation using IronPDF
public class IronPdfCreator : IPdfCreator
{    
    public void CreatePdf(string filePath,string content)
    {        // IronPDF-specific code for creating a PDF
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs(filePath);
    }
}
// Service adhering to Single Responsibility Principle
public class PdfGenerationService
{
    private readonly IPdfCreator pdfCreator;
    public PdfGenerationService(IPdfCreator pdfCreator)
    {
        this.pdfCreator = pdfCreator;
    }
    public void GeneratePdfDocument(string filePath)
    {
        // Business logic for generating content
        string content = "<p>This PDF is generated using IronPDF and follows SOLID principles.</p>";
        // Delegate the PDF creation to the injected dependency
        pdfCreator.CreatePdf(filePath,content);
        Console.WriteLine($"PDF generated successfully at {filePath}");
    }
}
class Program
{
    static void Main()
    {
        // Dependency injection using the Dependency Inversion Principle
        IPdfCreator ironPdfCreator = new IronPdfCreator();
        PdfGenerationService pdfService = new PdfGenerationService(ironPdfCreator);
        // Generate PDF using the service
        string pdfFilePath = "output.pdf";
        pdfService.GeneratePdfDocument(pdfFilePath);
        Console.ReadLine(); // To prevent the console window from closing immediately
    }
}
using IronPdf;
using System;
// Interface for PDF creation
public interface IPdfCreator
{
    void CreatePdf(string filePath,string content);
}
// Concrete implementation using IronPDF
public class IronPdfCreator : IPdfCreator
{    
    public void CreatePdf(string filePath,string content)
    {        // IronPDF-specific code for creating a PDF
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(content);
        pdf.SaveAs(filePath);
    }
}
// Service adhering to Single Responsibility Principle
public class PdfGenerationService
{
    private readonly IPdfCreator pdfCreator;
    public PdfGenerationService(IPdfCreator pdfCreator)
    {
        this.pdfCreator = pdfCreator;
    }
    public void GeneratePdfDocument(string filePath)
    {
        // Business logic for generating content
        string content = "<p>This PDF is generated using IronPDF and follows SOLID principles.</p>";
        // Delegate the PDF creation to the injected dependency
        pdfCreator.CreatePdf(filePath,content);
        Console.WriteLine($"PDF generated successfully at {filePath}");
    }
}
class Program
{
    static void Main()
    {
        // Dependency injection using the Dependency Inversion Principle
        IPdfCreator ironPdfCreator = new IronPdfCreator();
        PdfGenerationService pdfService = new PdfGenerationService(ironPdfCreator);
        // Generate PDF using the service
        string pdfFilePath = "output.pdf";
        pdfService.GeneratePdfDocument(pdfFilePath);
        Console.ReadLine(); // To prevent the console window from closing immediately
    }
}
Imports IronPdf
Imports System
' Interface for PDF creation
Public Interface IPdfCreator
	Sub CreatePdf(ByVal filePath As String, ByVal content As String)
End Interface
' Concrete implementation using IronPDF
Public Class IronPdfCreator
	Implements IPdfCreator

	Public Sub CreatePdf(ByVal filePath As String, ByVal content As String) Implements IPdfCreator.CreatePdf ' IronPDF-specific code for creating a PDF
		Dim renderer = New ChromePdfRenderer()
		Dim pdf = renderer.RenderHtmlAsPdf(content)
		pdf.SaveAs(filePath)
	End Sub
End Class
' Service adhering to Single Responsibility Principle
Public Class PdfGenerationService
	Private ReadOnly pdfCreator As IPdfCreator
	Public Sub New(ByVal pdfCreator As IPdfCreator)
		Me.pdfCreator = pdfCreator
	End Sub
	Public Sub GeneratePdfDocument(ByVal filePath As String)
		' Business logic for generating content
		Dim content As String = "<p>This PDF is generated using IronPDF and follows SOLID principles.</p>"
		' Delegate the PDF creation to the injected dependency
		pdfCreator.CreatePdf(filePath,content)
		Console.WriteLine($"PDF generated successfully at {filePath}")
	End Sub
End Class
Friend Class Program
	Shared Sub Main()
		' Dependency injection using the Dependency Inversion Principle
		Dim ironPdfCreator As IPdfCreator = New IronPdfCreator()
		Dim pdfService As New PdfGenerationService(ironPdfCreator)
		' Generate PDF using the service
		Dim pdfFilePath As String = "output.pdf"
		pdfService.GeneratePdfDocument(pdfFilePath)
		Console.ReadLine() ' To prevent the console window from closing immediately
	End Sub
End Class
VB   C#
  1. Interfaz IPdfCreator: Define un contrato para la creación de PDF, adhiriéndose al Principio de Responsabilidad Única al centrarse en una responsabilidad.

  2. Clase IronPdfCreator: Implementa IPdfCreator usando IronPDF para crear un PDF. Esta clase encapsula la lógica específica de la creación de PDF.

  3. Clase PdfGenerationService: Representa un servicio responsable de la generación de archivos PDF. Se adhiere al Principio de Responsabilidad Única manejando la lógica de negocio para la generación de contenido y delega la creación del PDF al IPdfCreator inyectado.

  4. Clase de programa (Principal): Demuestra el uso del Servicio y la dependencia inyectada, adhiriéndose al Principio de Inversión de Dependencia al depender de abstracciones. (interfaces) en lugar de implementaciones concretas.

    Para ejecutar este código, asegúrese de instalar la biblioteca IronPDF en su proyecto. Puede hacerlo utilizando NuGet Package Manager:

Install-Package IronPdf

Sustituya el contenido y la lógica de la clase PdfGenerationService por sus requisitos específicos.

3.1. Salida

Principios sólidos C# (Cómo funciona para desarrolladores) Figura 7

4. Conclusión

En conclusión, los principios SOLID proporcionan una base sólida para diseñar software mantenible y escalable en C#. Al comprender y aplicar estos principios, los desarrolladores pueden crear un código más modular, adaptable a los cambios y más accesible a las pruebas.

Cuando se trabaja con bibliotecas como IronPDF, la integración de los principios SOLID resulta aún más crucial. El diseño de clases que se adhieran a estos principios garantiza que su código siga siendo flexible y pueda evolucionar con los requisitos cambiantes de sus tareas relacionadas con PDF.

A medida que continúe desarrollando aplicaciones C#, tenga en cuenta los principios SOLID como directrices para crear código que resista el paso del tiempo. Tanto si trabaja en la generación de PDF como en las interacciones con bases de datos o en cualquier otro aspecto del desarrollo de software, los principios SOLID proporcionan una hoja de ruta para crear código funcional y mantenible a largo plazo.

Para saber más sobre elIronPDF biblioteca, Visitaaquí. Para obtener más información sobre la licencia y una prueba gratuita, visiteaquí.

< ANTERIOR
C# Switch Statement (Cómo funciona para los desarrolladores)
SIGUIENTE >
C# Json Serializer (Cómo funciona para desarrolladores)

¿Listo para empezar? Versión: 2024.10 acaba de salir

Descarga gratuita de NuGet Descargas totales: 11,173,334 Ver licencias >