AIDE .NET

Principes solides C# (Comment ça marche pour les développeurs)

Publié décembre 12, 2023
Partager:

Les principes SOLID sont cinq principes de conception qui, lorsqu'ils sont respectés, permettent de créer des entités logicielles robustes et faciles à maintenir. Robert C# Martin a introduit ces principes, qui sont devenus la pierre angulaire de la conception orientée objet. En C#, un langage de programmation orienté objet populaire développé par Microsoft, la compréhension et l'application des principes SOLID peuvent améliorer de manière significative la qualité du code.

Dans cet article, nous ferons un examen détaillé deDes principes solides en C# nous verrons également comment vous pouvez les utiliser pour écrire des structures de code réutilisables en créant des documents PDF à l'aide de l'outil de création de documents PDFIronPDF C# PDF Library (Bibliothèque PDF C#).

1. Les cinq principes SOLID en C# ;

Principes solides C# (Comment ça marche pour les développeurs) Figure 1

1.1. Principe de responsabilité unique (PRU)

Le principe de la responsabilité unique stipule qu'une classe ne doit avoir qu'une seule raison de changer, ce qui signifie qu'elle ne doit avoir qu'une seule responsabilité. En C#, ce principe encourage les développeurs à créer des classes axées sur une tâche spécifique. Par exemple, une classe chargée de gérer les opérations sur les fichiers ne doit pas être également responsable des connexions aux bases de données.

Principes solides C# (Comment ça marche pour les développeurs) Figure 2

1.2. Principe d'ouverture/fermeture (OCP)

Le principe ouvert/fermé suggère qu'une classe doit être ouverte à l'extension mais fermée à la modification, ce qui permet d'étendre le comportement d'un module sans modifier son code source. En C#, cela se fait souvent par le biais d'interfaces et de classes abstraites, ce qui permet de créer de nouvelles classes qui adhèrent aux contrats existants.

Principes solides C# (Comment ça marche pour les développeurs) Figure 3

1.3. Principe de substitution de Liskov (PSL)

La substitution de Liskov met l'accent sur le fait que les objets d'une superclasse doivent pouvoir être remplacés par des objets d'une sous-classe sans que la correction du programme n'en soit affectée. En C#, ce principe encourage le polymorphisme afin de garantir que les classes dérivées puissent utiliser leurs classes de base de manière interchangeable.

Principes solides C# (Comment ça marche pour les développeurs) Figure 4

1.4. Principe de séparation des interfaces (FAI)

Le principe de séparation des interfaces préconise l'utilisation de petites interfaces spécifiques plutôt que de grandes interfaces générales. En C#, ce principe décourage la création d'interfaces "grasses" qui obligent les classes d'implémentation à fournir des fonctionnalités dont elles n'ont pas besoin. Il encourage plutôt l'utilisation de plusieurs petites interfaces adaptées à des besoins spécifiques.

Principes solides C# (Comment ça marche pour les développeurs) Figure 5

1.5. Principe d'inversion de la dépendance (DIP)

L'inversion de dépendance promeut l'idée que les modules de haut niveau ne doivent pas dépendre des modules de bas niveau, mais que les deux doivent dépendre de la classe d'abstraction. En C#, il s'agit souvent d'utiliser l'injection de dépendances pour inverser le flux de contrôle traditionnel, ce qui permet d'obtenir un code plus souple et plus testable.

Principes solides C# (Comment ça marche pour les développeurs) Figure 6

2. Utilisation des principes de conception SOLID

Les principes SOLID fournissent une feuille de route pour la conception d'un code propre et facile à maintenir. Il ne faut pas les suivre aveuglément dans toutes les situations, mais les appliquer judicieusement en fonction du contexte d'une application donnée.

2.1. Principe de responsabilité unique (PRU)

Le principe de responsabilité unique peut s'avérer utile lors de la conception de classes dans une application C#. Le fait de veiller à ce que chaque classe ait une responsabilité unique rend le code plus modulaire et plus facile à comprendre. Cette modularité est bénéfique pour la maintenance et simplifie l'ajout de nouvelles fonctionnalités ou la correction de bogues sans affecter l'ensemble de la base de code.

2.2. Principe d'ouverture/fermeture (OCP)

Le principe ouvert/fermé s'applique lorsque le code doit être étendu mais pas modifié. Grâce aux interfaces et aux classes abstraites, les développeurs en C# peuvent créer des systèmes adaptables sans modifier le code existant.

2.3. Principe de substitution de Liskov (PSL)

Le principe de substitution de Liskov garantit que les classes dérivées peuvent être substituées de manière transparente à leurs classes de base, ce qui favorise une base de code plus souple et plus évolutive. L'application du principe de substitution de Liskov est particulièrement importante lorsque le polymorphisme est crucial.

2.4. Principe de séparation des interfaces (FAI)

Le principe de ségrégation des interfaces encourage la création de petites interfaces spécifiques adaptées aux besoins des classes qui les mettent en œuvre. Cette approche évite d'imposer des méthodes inutiles aux classes, ce qui favorise une conception plus efficace et plus facile à maintenir.

2.5. Principe d'inversion de la dépendance(DIP)

Le principe d'inversion de dépendance, par le biais de l'injection de dépendance, facilite la création de composants faiblement couplés dans une application C#. La mise en œuvre de ce principe réduit la complexité globale du code et améliore sa testabilité.

2.6. Exemple d'application

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#

Dans cet extrait de code, on trouve une application claire de la programmation orientée objet(OOP) les principes de SOLID, en particulier, sont évidents. La classe Shape sert de classe de base abstraite, définissant le concept commun des formes et déclarant la méthode abstraite Area(). Le terme "classe enfant ou classe dérivée" fait référence aux classes Cercle et Rectangle, car elles héritent de la classe parentale commune. Circle et Rectangle agissent comme des classes dérivées, étendant la fonctionnalité de la classe de base abstraite et fournissant des implémentations concrètes de la fonction Area() méthode. En outre, le code illustre les principes de la SOLID, tels que le principe de la responsabilité unique(SRP)où chaque classe a une responsabilité distincte, et le principe d'inversion de la dépendance(DIP)comme le montre l'utilisation de l'interface ILogger, ce qui favorise la flexibilité et la facilité de maintenance.

3. Application du principe SOLID à IronPDF

Maintenant que nous avons exploré les principes SOLID en théorie, plongeons dans leur application pratique en C# à l'aide d'IronPDF, une bibliothèque populaire permettant de travailler avec des PDF. IronPDF permet aux développeurs de créer, manipuler et traiter des documents PDF de manière transparente en C#. En intégrant les principes SOLID, nous pouvons nous assurer que notre code reste modulaire, extensible et maintenable.

Prenons l'exemple du principe de responsabilité unique. Lorsque l'on travaille avec IronPDF, il est utile de disposer de classes qui gèrent des aspects spécifiques de la génération ou de la manipulation de fichiers PDF. Par exemple, une classe peut créer des documents PDF, tandis qu'une autre se concentre sur l'ajout et la mise en forme de contenu.

Le principe d'ouverture/fermeture nous encourage à concevoir nos cours sur les PDF en gardant à l'esprit l'extension. Au lieu de modifier les classes existantes pour les adapter aux nouvelles fonctionnalités, nous pouvons créer des classes qui étendent ou mettent en œuvre les interfaces existantes. Ainsi, nous respectons le principe sans compromettre la fonctionnalité existante.

Le principe de substitution de Liskov entre en jeu lorsqu'il s'agit de différents types d'éléments PDF. Qu'il s'agisse de texte, d'images ou d'annotations, la conception de classes qui adhèrent à une interface commune permet une substitution transparente et améliore la flexibilité de notre code de génération de PDF. Le principe de ségrégation des interfaces est essentiel lors de la définition des contrats pour les classes qui interagissent avec IronPDF. En créant de petites interfaces spécifiques adaptées aux besoins des différents composants, nous évitons les dépendances inutiles et garantissons que les classes n'implémentent que les méthodes dont elles ont besoin.

Enfin, l'application du principe d'inversion de la dépendance peut améliorer la testabilité et la maintenabilité de notre code. En injectant des dépendances plutôt qu'en les codant en dur, nous créons un système à couplage plus lâche, plus facile à mettre à jour et à étendre.

Illustrons ces concepts par un exemple de code simple utilisant 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. Interface IPdfCreator: Définit un contrat pour la création de PDF, adhérant au principe de responsabilité unique en se concentrant sur une seule responsabilité.

  2. classe IronPdfCreator: Implémente IPdfCreator** en utilisant IronPDF pour créer un PDF. Cette classe encapsule la logique spécifique à la création de PDF.

  3. classe PdfGenerationService: Représente un service responsable de la génération de PDF. Il adhère au principe de la responsabilité unique en gérant la logique commerciale pour la génération du contenu et délègue la création du PDF au IPdfCreator** injecté.

  4. Classe de programme(Principal): Démontre l'utilisation du service et de la dépendance injectée, en adhérant au principe d'inversion de dépendance en dépendant des abstractions(interfaces) plutôt que des implémentations concrètes.

    Pour exécuter ce code, assurez-vous d'installer la bibliothèque IronPDF dans votre projet. Pour ce faire, vous pouvez utiliser le gestionnaire de paquets NuGet :

Install-Package IronPdf

Remplacez le contenu et la logique de la classe PdfGenerationService par vos besoins spécifiques.

3.1. Sortie

Principes solides C# (Comment ça marche pour les développeurs) Figure 7

4. Conclusion

En conclusion, les principes SOLID constituent une base solide pour la conception de logiciels maintenables et évolutifs en C#. En comprenant et en appliquant ces principes, les développeurs peuvent créer un code plus modulaire, adaptable aux changements et plus accessible aux tests.

Lorsque l'on travaille avec des bibliothèques comme IronPDF, l'intégration des principes SOLID devient encore plus cruciale. La conception de classes qui adhèrent à ces principes garantit que votre code reste flexible et peut évoluer avec les exigences changeantes de vos tâches liées au format PDF.

Alors que vous continuez à développer des applications C#, gardez à l'esprit les principes SOLID en tant que lignes directrices pour la création d'un code qui résiste à l'épreuve du temps. Que vous travailliez sur la génération de PDF, les interactions avec les bases de données ou tout autre aspect du développement logiciel, les principes SOLID constituent une feuille de route pour la création d'un code fonctionnel et facile à maintenir à long terme.

Pour en savoir plus sur le projetBibliothèque IronPDFvisitez le siteDocumentation IronPDF. Pour en savoir plus sur la licence et obtenir une version d'essai gratuite, rendez-vous sur le sitePage de licences IronPDF.

< PRÉCÉDENT
Déclaration de commutation C# (Comment cela fonctionne pour les développeurs)
SUIVANT >
C# Json Serializer (Comment ça marche pour les développeurs)