Explorez la programmation orientée objet avec des classes et des objets
Dans ce didacticiel, vous allez créer une application console et voir les fonctionnalités orientées objet de base qui font partie du langage C#.
Prérequis
- Nous vous recommandons Visual Studio pour Windows. Vous pouvez télécharger une version gratuite à partir de la page téléchargements de Visual Studio. Visual Studio inclut le Kit de développement logiciel (SDK) .NET.
- Vous pouvez également utiliser l’éditeur Visual Studio Code avec le DevKit C#. Vous devez installer le dernier SDK .NET séparément.
- Si vous préférez un autre éditeur, vous devez installer le dernier kit SDK .NET.
Créer votre application
Dans une fenêtre du terminal, créez un répertoire nommé Classes. Vous y créerez votre application. Sélectionnez ce répertoire et tapez dotnet new console
dans la fenêtre de console. Cette commande crée votre application. Ouvrez Program.cs. Il doit se présenter comme suit :
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Dans ce tutoriel, vous allez créer des types qui représentent un compte bancaire. Les développeurs définissent généralement chaque classe dans un fichier texte différent. Cela simplifie la gestion au fur et à mesure qu’un programme augmente en taille. Créez un fichier nommé BankAccount.cs dans le répertoire Classes.
Ce fichier contiendra la définition d’un compte bancaire. La programmation orientée objet organise le code en créant des types sous la forme de classes. Ces classes contiennent le code qui représente une entité spécifique. La classe BankAccount
représente un compte bancaire. Le code implémente des opérations spécifiques à travers des méthodes et des propriétés. Dans ce tutoriel, le compte bancaire prend en charge le comportement suivant :
- Il contient un numéro à 10 chiffres qui identifie le compte bancaire de manière unique.
- Il contient une chaîne qui stocke le nom du ou des détenteurs.
- Le solde peut être récupéré.
- Il accepte les dépôts.
- Il accepte les retraits.
- Le solde initial doit être positif.
- Les retraits ne peuvent pas générer un solde négatif.
Définir le type de compte bancaire
Vous pouvez commencer par créer les éléments de base d’une classe définissant ce comportement. Créez un fichier à l’aide de la commande File:New. Nommez-le BankAccount.cs. Ajoutez le code suivant dans le fichier BankAccount.cs :
namespace Classes;
public class BankAccount
{
public string Number { get; }
public string Owner { get; set; }
public decimal Balance { get; }
public void MakeDeposit(decimal amount, DateTime date, string note)
{
}
public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
}
}
Avant de poursuivre, examinons ce que vous venez de créer. La déclaration namespace
permet d’organiser logiquement votre code. Ce tutoriel étant relativement petit, vous allez placer tout le code dans un même espace de noms.
public class BankAccount
définit la classe, ou le type, que vous créez. Tout ce qui est situé entre {
et }
après la déclaration de classe définit l’état et le comportement de la classe. La classe BankAccount
a cinq membres. Les trois premiers sont des propriétés. Les propriétés sont des éléments de données qui peuvent avoir un code qui applique la validation ou d’autres règles. Les deux derniers sont des méthodes. Les méthodes sont des blocs de code qui effectuent une fonction unique. La lecture des noms de chacun des membres doit fournir suffisamment d’informations pour vous permettre (ou à tout autre développeur) de comprendre ce que fait la classe.
Ouvrir un nouveau compte
La première fonctionnalité à implémenter est l’ouverture d’un compte bancaire. Quand un client ouvre un compte, il doit fournir un solde initial, ainsi que des informations sur le ou les détenteurs du compte.
La création d’un objet de type BankAccount
implique la définition d’un constructeur qui affecte ces valeurs. Un constructeur est un membre qui porte le même nom que la classe. Il est utilisé pour initialiser des objets de ce type de classe. Ajoutez le constructeur suivant au type BankAccount
. Placez le code suivant au-dessus de la déclaration de MakeDeposit
:
public BankAccount(string name, decimal initialBalance)
{
this.Owner = name;
this.Balance = initialBalance;
}
Le code précédent identifie les propriétés de l’objet en cours de construction en incluant le qualificateur this
. Ce qualificateur est généralement facultatif et omis. Vous auriez également pu écrire :
public BankAccount(string name, decimal initialBalance)
{
Owner = name;
Balance = initialBalance;
}
Le qualificateur this
est requis uniquement quand une variable ou un paramètre local porte le même nom que ce champ ou cette propriété. Le qualificateur this
est omis dans le reste de cet article, sauf s’il est nécessaire.
Les constructeurs sont appelés quand vous créez un objet à l’aide de new
. Remplacez la ligne Console.WriteLine("Hello World!");
dans Program.cs par le code suivant (remplacez <name>
par votre nom) :
using Classes;
var account = new BankAccount("<name>", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
Exécutons ce que vous avez créé à ce stade. Si vous utilisez Visual Studio, sélectionnez Démarrer sans débogage dans le menu Déboguer. Si vous utilisez une ligne de commande, tapez dotnet run
dans le répertoire où vous avez créé votre projet.
Avez-vous remarqué que le numéro de compte est vide ? L’heure est venue de traiter ce point. Le numéro de compte doit être assigné une fois l’objet construit. Mais ce ne devrait pas être à l’appelant de le créer. Le code de la classe BankAccount
devrait savoir comment assigner de nouveaux numéros de compte. Un moyen simple consiste à commencer avec un nombre à 10 chiffres. Incrémentez-le chaque fois qu’un compte est créé. Enfin, stockez le numéro de compte actuel quand un objet est construit.
Ajoutez une déclaration de membre à la classe BankAccount
. Placez la ligne de code suivante après l’accolade ouvrante {
au début de la classe BankAccount
:
private static int s_accountNumberSeed = 1234567890;
accountNumberSeed
est un membre de données. Celui-ci est private
, ce qui signifie qu’il est uniquement accessible par code dans la classe BankAccount
. C’est un moyen de séparer les responsabilités publiques (comme le fait de disposer d’un numéro de compte) de l’implémentation privée (c’est-à-dire la façon dont les numéros de compte sont générés). Il est également static
, ce qui signifie qu’il est partagé par tous les objets BankAccount
. La valeur d’une variable non statique est unique pour chaque instance de l’objet BankAccount
. Le accountNumberSeed
est un private static
champ et a donc le s_
préfixe conformément aux conventions de nommage C#. Le s
dénotant static
et _
dénotant private
le champ. Ajoutez les deux lignes suivantes au constructeur pour affecter le numéro de compte. Placez-les après la ligne qui stipule this.Balance = initialBalance
:
Number = s_accountNumberSeed.ToString();
s_accountNumberSeed++;
Tapez dotnet run
pour afficher les résultats.
Créer des dépôts et des retraits
La classe de votre compte bancaire doit accepter les dépôts et les retraits pour fonctionner correctement. Nous allons implémenter des dépôts et des retraits en créant un journal de chaque transaction du compte. Le suivi de chaque transaction présente plusieurs avantages par rapport à la simple mise à jour du solde à chaque transaction. L’historique peut être utilisé pour auditer toutes les transactions et gérer les soldes au quotidien. Le calcul du solde à partir de l’historique de toutes les transactions, lorsque nécessaire, garantit que toute erreur corrigée dans une transaction individuelle sera reflétée correctement dans le solde lors du calcul suivant.
Commençons par créer un type pour représenter une transaction. La transaction est un type simple qui n’a aucune responsabilité. Il a besoin de quelques propriétés. Créez un fichier nommé Transaction.cs. Ajoutez-lui le code suivant :
namespace Classes;
public class Transaction
{
public decimal Amount { get; }
public DateTime Date { get; }
public string Notes { get; }
public Transaction(decimal amount, DateTime date, string note)
{
Amount = amount;
Date = date;
Notes = note;
}
}
Nous allons maintenant ajouter une List<T> d’objets Transaction
à la classe BankAccount
. Ajoutez la déclaration suivante après le constructeur dans votre fichier BankAccount.cs :
private List<Transaction> _allTransactions = new List<Transaction>();
À présent, nous allons calculer correctement Balance
. Le solde actuel peut être obtenu en additionnant les valeurs de toutes les transactions. Dans l’état actuel du code, vous ne pouvez obtenir que le solde initial du compte. Vous devrez donc mettre à jour la propriété Balance
. Remplacez la ligne public decimal Balance { get; }
dans BankAccount.cs par le code suivant :
public decimal Balance
{
get
{
decimal balance = 0;
foreach (var item in _allTransactions)
{
balance += item.Amount;
}
return balance;
}
}
Cet exemple montre un aspect important des propriétés. Vous calculez à présent le solde quand un autre programmeur en demande la valeur. Votre calcul énumère toutes les transactions et retourne la somme en tant que solde actuel.
Implémentez ensuite les méthodes MakeDeposit
et MakeWithdrawal
. Ces méthodes appliquent les deux règles finales : le solde initial doit être positif et un retrait ne doit pas créer un solde négatif.
Ces règles introduisent le concept d’exceptions. La manière standard d’indiquer qu’une méthode ne peut pas effectuer correctement son travail consiste à lever une exception. Le type d’exception et le message associé décrivent l’erreur. Ici, la méthode MakeDeposit
lève une exception si le montant du dépôt n’est pas supérieur à 0. La méthode MakeWithdrawal
lève une exception si le montant du retrait n’est pas supérieur à 0 ou si l’application du retrait entraîne un solde négatif. Ajoutez le code suivant après la déclaration de la liste _allTransactions
:
public void MakeDeposit(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
}
var deposit = new Transaction(amount, date, note);
_allTransactions.Add(deposit);
}
public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
}
if (Balance - amount < 0)
{
throw new InvalidOperationException("Not sufficient funds for this withdrawal");
}
var withdrawal = new Transaction(-amount, date, note);
_allTransactions.Add(withdrawal);
}
L’throw
instruction lève une exception. L’exécution du bloc actuel se termine et le contrôle est transféré au premier bloc correspondant catch
trouvé dans la pile des appels. Vous ajouterez un bloc catch
pour tester ce code un peu plus tard.
Le constructeur devrait obtenir une modification lui permettant d’ajouter une transaction initiale au lieu de mettre directement le solde à jour. Étant donné que vous avez déjà écrit la méthode MakeDeposit
, appelez-la à partir de votre constructeur. Le constructeur terminé doit être semblable à ce qui suit :
public BankAccount(string name, decimal initialBalance)
{
Number = s_accountNumberSeed.ToString();
s_accountNumberSeed++;
Owner = name;
MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}
DateTime.Now est une propriété qui retourne la date et l'heure actuelles. Testez ce code en ajoutant quelques dépôts et retraits dans votre méthode Main
, à la suite du code qui crée un nouveau BankAccount
:
account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(100, DateTime.Now, "Friend paid me back");
Console.WriteLine(account.Balance);
Ensuite, vérifiez que vous interceptez des conditions d’erreur en essayant de créer un compte avec un solde négatif. Ajoutez le code suivant après le code précédent que vous venez d’ajouter :
// Test that the initial balances must be positive.
BankAccount invalidAccount;
try
{
invalidAccount = new BankAccount("invalid", -55);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine("Exception caught creating account with negative balance");
Console.WriteLine(e.ToString());
return;
}
Vous utilisez l’instruction try-catch
pour marquer un bloc de code pouvant lever des exceptions et intercepter les erreurs que vous attendez. Vous pouvez utiliser la même technique pour tester le code qui lève une exception pour un solde négatif. Ajoutez le code suivant avant la déclaration de invalidAccount
dans votre méthode Main
:
// Test for a negative balance.
try
{
account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw");
}
catch (InvalidOperationException e)
{
Console.WriteLine("Exception caught trying to overdraw");
Console.WriteLine(e.ToString());
}
Enregistrez le fichier et tapez dotnet run
pour effectuer un essai.
Test : consigner toutes les transactions
Pour terminer ce tutoriel, vous pouvez écrire la méthode GetAccountHistory
qui crée une string
pour l’historique des transactions. Ajoutez cette méthode au type BankAccount
:
public string GetAccountHistory()
{
var report = new System.Text.StringBuilder();
decimal balance = 0;
report.AppendLine("Date\t\tAmount\tBalance\tNote");
foreach (var item in _allTransactions)
{
balance += item.Amount;
report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
}
return report.ToString();
}
L’historique utilise la classe StringBuilder pour mettre en forme une chaîne contenant une ligne pour chaque transaction. Vous avez vu le code de mise en forme de chaîne précédemment dans ces tutoriels. Vous pouvez observer le nouveau caractère \t
. Celui-ci insère une tabulation pour mettre en forme la sortie.
Ajoutez cette ligne pour effectuer un essai dans Program.cs :
Console.WriteLine(account.GetAccountHistory());
Exécutez votre programme pour voir les résultats.
Étapes suivantes
Si vous êtes bloqué, vous pouvez afficher la source de ce didacticiel dans notre dépôt GitHub.
Vous pouvez continuer avec le didacticiel sur la programmation orientée objet.
Pour en savoir plus sur ces concepts, consultez les articles :