Ne regardez pas tout de suite la correction. Faites le TP. Il est important de manipuler les classes. Vous allez faire ça très régulièrement. Cela doit devenir un réflexe et pour que cela le devienne, il faut pratiquer !
Toujours est-il que voici ma correction. Peut-être que le plus dur est de modéliser correctement l’application ?
Il y a plusieurs solutions bien sûr pour créer ce petit programme, voici celle que je propose.
Tout d’abord, nous devons manipuler des comptes courant et des comptes épargne entreprise, qui sont des sortes de comptes.
On en déduit qu’un compte courant hérite d’un compte. De même, un compte épargne entreprise hérite également d’un compte. D’ailleurs, un compte a-t-il vraiment une raison d’être à part entière ? Nous ne créons jamais de compte « généraliste », seulement des comptes spécialisés. Nous allons donc créer la classe compte en tant que classe abstraite.
Ce qui nous donnera les classes suivantes :
Code : C# | public abstract class Compte
{
}
public class CompteCourant : Compte
{
}
public class CompteEpargneEntreprise : Compte
{
}
|
Nous avons également dit qu’un compte était composé d’une liste d’opérations qui possèdent un montant et un type de mouvement. Le type de mouvement pouvant prendre 2 valeurs, il parait logique d’utiliser une énumération :
Code : C# | public enum Mouvement
{
Credit,
Debit
}
|
La classe d’opération étant :
Code : C# | public class Operation
{
public Mouvement TypeDeMouvement { get; set; }
public decimal Montant { get; set; }
}
|
Voilà pour la base.
Ensuite, la classe
Compte doit posséder un nom de propriétaire et un solde qui peut être redéfini dans la classe
CompteEpargneEntreprise. Ce solde est calculé à partir d’une liste d’opérations. Le solde est donc une propriété en lecture seule, virtuelle car nécessitant d’être redéfinie :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | public abstract class Compte
{
protected List<Operation> listeOperations;
public string Proprietaire { get; set; }
public virtual decimal Solde
{
get
{
decimal total = 0;
foreach (Operation operation in listeOperations)
{
if (operation.TypeDeMouvement == Mouvement.Credit)
total += operation.Montant;
else
total -= operation.Montant;
}
return total;
}
}
}
|
La liste des opérations est une variable membre, déclarée en
protected car nous allons en avoir besoin dans la classe
CompteCourant qui en hérite, afin d’afficher un résumé des opérations.
La propriété
Solde n’est pas très compliquée en soit, il suffit de parcourir la liste des opérations et en fonction du type de mouvement, ajouter ou retrancher le montant. Comme c’est une propriété en lecture seule, seul le
get est défini.
N’oubliez pas que la liste doit être initialisée avant d’être utilisée, sinon nous aurons une erreur. Le constructeur est un endroit approprié pour le faire :
Code : C# | public abstract class Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public Compte()
{
listeOperations = new List<Operation>();
}
}
|
La classe doit ensuite posséder des méthodes permettant de créditer ou de débiter le compte, ce qui donne :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | public abstract class Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public void Crediter(decimal montant)
{
Operation operation = new Operation { Montant = montant, TypeDeMouvement = Mouvement.Credit};
listeOperations.Add(operation);
}
public void Crediter(decimal montant, Compte compte)
{
Crediter(montant);
compte.Debiter(montant);
}
public void Debiter(decimal montant)
{
Operation operation = new Operation { Montant = montant, TypeDeMouvement = Mouvement.Debit };
listeOperations.Add(operation);
}
public void Debiter(decimal montant, Compte compte)
{
Debiter(montant);
compte.Crediter(montant);
}
}
|
Le principe est de créer une opération et de l’ajouter à la liste des opérations. L’astuce ici consiste à réutiliser les méthodes de la classe pour écrire les autres formes des méthodes, ce qui simplifie le travail et facilitera les éventuelles futures opérations de maintenance.
Enfin, chaque classe dérivée de la classe
Compte doit afficher un résumé du compte. Nous pouvons donc forcer ces classes à devoir implémenter cette méthode en utilisant une méthode abstraite :
Code : C# | public abstract class Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public abstract void AfficherResume();
}
|
Voilà pour la classe
Compte. En toute logique, c’est elle qui contient le plus de méthodes afin de factoriser le maximum de code commun dans la classe mère.
Passons à la classe
CompteEpargneEntreprise, qui hérite de la classe
Compte. Elle possède un taux d’abondement qui est défini à la création du compte. Il est donc ici intéressant de forcer le positionnement de ce taux lors de la création de la classe, c'est-à-dire en utilisant un constructeur avec un paramètre :
Code : C# | public class CompteEpargneEntreprise : Compte
{
private double tauxAbondement;
public CompteEpargneEntreprise(double taux)
{
tauxAbondement = taux;
}
}
|
Ce taux est utilisé pour calculer le solde du compte en faisant la somme de toutes les opérations et en appliquant le taux. Ce qui revient à appeler le calcul du solde de la classe mère et à lui appliquer le taux. Nous substituons donc la propriété
Solde et utilisons le calcul fait dans la classe
Compte:
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14 | public class CompteEpargneEntreprise : Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public override decimal Solde
{
get
{
return base.Solde * (decimal)(1 + tauxAbondement);
}
}
}
|
Rien de plus simple, en utilisant le mot-clé
base pour appeler le solde de la classe mère. Vous noterez également que nous avons eu besoin de caster le taux qui est un double afin de pouvoir le multiplier à un décimal.
Enfin, cette classe se doit de fournir une implémentation de la méthode
AfficherResume() :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | public class CompteEpargneEntreprise : Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public override void AfficherResume()
{
Console.WriteLine("########################################################");
Console.WriteLine("Compte épargne entreprise de " + Proprietaire);
Console.WriteLine("\tSolde : " + Solde);
Console.WriteLine("\tTaux : " + tauxAbondement);
Console.WriteLine("\n\nOpérations :");
foreach (Operation operation in listeOperations)
{
if (operation.TypeDeMouvement == Mouvement.Credit)
Console.Write("\t+");
else
Console.Write("\t-");
Console.WriteLine(operation.Montant);
}
Console.WriteLine("########################################################");
}
}
|
Il s’agit d’une banale méthode d’affichage où nous parcourons la liste contenant les opérations et affichons le montant en fonction du type de mouvement.
Voilà pour la classe
CompteEpargneEntreprise.
Il ne reste plus que la classe
CompteCourant qui doit également dériver de
Compte :
Code : C# | public class CompteCourant : Compte
{
}
|
Un compte courant doit posséder un découvert autorisé, défini à la création du compte courant. Nous utilisons comme avant un constructeur avec un paramètre :
Code : C# | public class CompteCourant : Compte
{
private decimal decouvertAutorise;
public CompteCourant(decimal decouvert)
{
decouvertAutorise = decouvert;
}
}
|
Il ne restera plus qu’à fournir une implémentation de la méthode d’affichage du résumé :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | public class CompteCourant : Compte
{
// [...]
// [Code précédent enlevé pour plus de lisibilité]
// [...]
public override void AfficherResume()
{
Console.WriteLine("*******************************************");
Console.WriteLine("Compte courant de " + Proprietaire);
Console.WriteLine("\tSolde : " + Solde);
Console.WriteLine("\tDécouvert autorisé : " + decouvertAutorise);
Console.WriteLine("\n\nOpérations :");
foreach (Operation operation in listeOperations)
{
if (operation.TypeDeMouvement == Mouvement.Credit)
Console.Write("\t+");
else
Console.Write("\t-");
Console.WriteLine(operation.Montant);
}
Console.WriteLine("*******************************************");
}
}
|
Voilà pour nos objets. Cela en fait un petit paquet. Mais ce n’est pas fini, il faut maintenant créer des comptes et faire des opérations.
L’énoncé consiste à faire les instanciations suivantes, depuis notre méthode
Main() :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | CompteCourant compteNicolas = new CompteCourant(2000) { Proprietaire = "Nicolas" };
CompteEpargneEntreprise compteEpargneNicolas = new CompteEpargneEntreprise(0.02) { Proprietaire = "Nicolas" };
CompteCourant compteJeremie = new CompteCourant(500) { Proprietaire = "Jérémie" };
compteNicolas.Crediter(100);
compteNicolas.Debiter(50);
compteEpargneNicolas.Crediter(20, compteNicolas);
compteEpargneNicolas.Crediter(100);
compteEpargneNicolas.Debiter(20, compteNicolas);
compteJeremie.Debiter(500);
compteJeremie.Debiter(200, compteNicolas);
Console.WriteLine("Solde compte courant de " + compteNicolas.Proprietaire + " : " + compteNicolas.Solde);
Console.WriteLine("Solde compte épargne de " + compteEpargneNicolas.Proprietaire + " : " + compteEpargneNicolas.Solde);
Console.WriteLine("Solde compte courant de " + compteJeremie.Proprietaire + " : " + compteJeremie.Solde);
Console.WriteLine("\n");
|
Rien d’extraordinaire.
Il ne reste plus qu’à afficher le résumé des deux comptes demandés :
Code : C# | Console.WriteLine("Résumé du compte de Nicolas");
compteNicolas.AfficherResume();
Console.WriteLine("\n");
Console.WriteLine("Résumé du compte épargne de Nicolas");
compteEpargneNicolas.AfficherResume();
Console.WriteLine("\n");
|
Nous en avons fini avec la première partie du TP !
Si vous avez bien compris comment construire des classes, comment les faire hériter entre elles et les interfaces, ce TP n’a pas dû vous poser trop de problèmes.