Syllabus POO2 Suite
Syllabus POO2 Suite
Syllabus POO2 Suite
Nous avons ici la définition d'une classe, donc d'un type de données. Lorsqu'on
va créer des variables de ce type, on les appellera des objets ou des instances de
classes. Une classe est donc un moule à partir duquel sont construits des objets.
Les membres ou champs d'une classe peuvent être des données (attributs), des
méthodes (fonctions), des propriétés. Les propriétés sont des méthodes particulières
servant à connaître ou fixer la valeur d'attributs de l'objet. Ces champs peuvent être
accompagnés de l'un des trois mots clés suivants :
- Privé Un champ privé (private) n'est accessible que par les seules méthodes
internes de la classe
- Public Un champ public (public) est accessible par toute fonction définie ou
non au sein de la classe
- Protégé Un champ protégé (protected) n'est accessible que par les seules
méthodes internes de la classe ou d'un objet dérivé (voir ultérieurement le
concept d'héritage).
En général, les données d'une classe sont déclarées privées alors que ses
méthodes et propriétés sont déclarées publiques. Cela signifie que l'utilisateur d'un
objet (le programmeur)
• n'aura pas accès directement aux données privées de l'objet
• pourra faire appel aux méthodes publiques de l'objet et notamment à celles qui
donneront accès à ses données privées.
La syntaxe de déclaration d'un objet est la suivante :
Quel est le rôle de la méthode initialise ? Parce que nom, prenom et age sont des
données privées de la classe personne, les instructions :
personne p1;
p1.prenom="Jean";
p1.nom="Dupont";
p1.age=30;
Sont illégales. Il nous faut initialiser un objet de type personne via une méthode
publique. C'est le rôle de la méthode initialise. On écrira :
personne p1;
p1.initialise("Jean","Dupont",30);
p1.initialise("Jean","Dupont",30);
Est valide.
5.1.5. Le mot clé this
Regardons le code de la méthode initialise :
p1.initialise("Jean","Dupont",30);
C'est la méthode initialise de l'objet p1 qui est appelée. Lorsque dans cette
méthode, on référence l'objet this, on référence en fait l'objet p1. La méthode initialise
aurait aussi pu être écrite comme suit :
this.age=age;
Où age désigne un attribut de l'objet courant ainsi que le paramètre age reçu
par la méthode. Il faut alors lever l'ambiguïté en désignant l'attribut age par this.age.
Exemple 2 :
namespace Appform
{
class Addition
{
private double nb1, nb2, resultat;
public Addition() { }
public void RecuperationValeur(double nombre1, double nombre2) {
this.nb1 = nombre1;
this.nb2 = nombre2;
}
public double MonAddition()
{
this.resultat = nb1 + nb2;
return this.resultat;
}
}
}
----------------------------------------------------------------------------------------
---
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Appform
{
class Division
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) Page |-6-
{
private double nb1, nb2, resultat;
public Division() { }
public void RecuperationValeur(double nombre1, double nombre2) {
this.nb1 = nombre1;
this.nb2 = nombre2;
}
public double MaDivision()
{
this.resultat = nb1 / nb2;
return this.resultat;
}
}
}
----------------------------------------------------------------------------------------
--
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Appform
{
class Multiplication
{
private double nb1, nb2, resultat;
public Multiplication() { }
public void RecuperationValeur(double nombre1, double nombre2) {
this.nb1 = nombre1;
this.nb2 = nombre2;
}
public double MaMultiplication()
{
this.resultat = nb1 * nb2;
return this.resultat;
}
}
}
--------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Appform
{
class Soustraction
{
private double nb1, nb2, resultat;
public Soustraction() { }
public void RecuperationValeur(double nombre1, double nombre2) {
this.nb1 = nombre1;
this.nb2 = nombre2;
}
public double MaSoustraction()
{
this.resultat = nb1 - nb2;
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) Page |-7-
return this.resultat;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Appform
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
textBox3.Text = Convert.ToString(calcul.MaDivision());
}
}
}
}
Voici un test de la nouvelle classe personne, celle-ci ayant été compilée dans
personne.dll comme il a été expliqué précédemment :
ou
classe objet;
: public C(). Les attributs de l'objet sont alors initialisés avec des valeurs par défaut.
C'est ce qui s'est passé lorsque dans les programmes précédents,
où on avait écrit :
personne p1;
p1=new personne();
p1=null
Lorsqu'on écrit :
personne p2=p1;
On initialise le pointeur p2 : il "pointe" sur le même objet (il désigne le même objet)
que le pointeur p1. Ainsi si on modifie l'objet "pointé" (ou référencé) par p1, on
modifie celui référencé par p2.
Lorsqu'on écrit :
Il y a création d'un nouvel objet, copie de l'objet référencé par p1. Ce nouvel objet
sera référencé par p3. Si on modifie l'objet "pointé" (ou référencé) par p1, on ne
modifie en rien celui référencé par p3. C'est ce que montrent les résultats obtenus.
p1=Jean,Dupont,30
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) P a g e | - 12 -
p2=Jean,Dupont,30
p3=Jean,Dupont,30
p1=Micheline,Benoît,67
p2=Micheline,Benoît,67
p3=Jean,Dupont,30
using System;
public class personne{
// attributs
private String _prenom;
private String _nom;
private int _age;
// constructeurs
public personne(String P, String N, int age){
this._prenom=P;
this._nom=N;
this._age=age;
}
public personne(personne P){
this._prenom=P._prenom;
this._nom=P._nom;
this._age=P._age;
}
// identifie
public void identifie(){
Console.Out.WriteLine(_prenom+","+_nom+","+_age);
}
// propriétés
public string prenom{
get { return _prenom; }
set { _prenom=value; }
}//prenom
public string nom{
get { return _nom; }
set { _nom=value; }
}//nom
public int age{
get { return _age; }
set {
// age valide ?
if(value>=0){
_age=value;
} else
throw new Exception("âge ("+value+") invalide");
}//if
}//age
}//classe
Une propriété permet de lire (get) ou de fixer (set) la valeur d'un attribut. Dans
notre exemple, nous avons préfixé les noms des attributs du signe _ afin que les
propriétés portent le nom des attributs primitifs. En effet, une propriété ne peut
porter le même nom que l'attribut qu'elle gère car alors il y a un conflit de noms
dans la classe. Nous avons donc appelé nos attributs _prenom, _nom, _age et modifié
les constructeurs et méthodes en conséquence. Nous avons ensuite créé trois
propriétés nom, prenom et age. Une propriété est déclarée comme suit :
Où type doit être le type de l'attribut géré par la propriété. Elle peut avoir deux
méthodes appelées get et set. La méthode get est habituellement chargée de rendre
la valeur de l'attribut qu'elle gère (elle pourrait rendre autre chose, rien ne
l'empêche). La méthode set reçoit un paramètre appelé value qu'elle affecte
normalement à l'attribut qu'elle gère. Elle peut en profiter pour faire des vérifications
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) P a g e | - 15 -
Dans l'instruction
Console.Out.WriteLine("P=("+P.prenom+","+P.nom+","+P.age+")");
On cherche à avoir les valeurs des propriétés prenom, nom et age de la personne P.
C'est la méthode get de ces propriétés qui est alors appelée et qui rend la valeur de
l'attribut qu'elles gèrent.
Dans l'instruction
P.age=56;
On veut fixer la valeur de la propriété age. C'est alors la méthode set de cette
propriété qui est alors appelée. Elle recevra 56 dans son paramètre value.
Une propriété P d'une classe C qui ne définirait que la méthode get est dite en lecture
seule. Si c’est un objet de classe C, l'opération c.P=valeur sera alors refusée par le
compilateur.
Les propriétés nous permettent donc de manipuler des attributs privés comme
s'ils étaient publics.
Si une référence d'objet R1 est transmise à une fonction, elle sera recopiée
dans le paramètre formel correspondant R2. Aussi les références R2 et R1 désignent-
elles le même objet. Si la fonction modifie l'objet pointé par R2, elle modifie
évidemment celui référencé par R1 puisque c'est le même.
La méthode modifie est déclarée static parce que c'est une méthode de classe
: on n'a pas à la préfixer par un objet pour l'appeler.
Personne est appelée la classe parent (ou mère) et enseignant la classe dérivée (ou
fille). Un objet enseignant a toutes les qualités d'un objet personne : il a les mêmes
attributs et les mêmes méthodes. Ces attributs et méthodes de la classe parent ne
sont pas répétées dans la définition de la classe fille : on se contente d'indiquer les
attributs et méthodes rajoutés par la classe fille :
}//age
public string identite{
get { return "personne("+_prenom+","+_nom+","+age+")";}
}
}//classe
La déclaration sera :
public class enseignant : personne {
La déclaration
public enseignant(String P, String N, int age,int section) : base(P,N,age) {
C'est impossible. La classe personne a déclaré privés (private) ses trois champs
_prenom, _nom et _age. Seuls des objets de la même classe ont un accès direct à ces
champs. Tous les autres objets, y compris des objets fils comme ici, doivent passer
par des méthodes publiques pour y avoir accès. Cela aurait été différent si la classe
personne avait déclaré protégés (protected) les trois champs : elle autorisait alors des
classes dérivées à avoir un accès direct aux trois champs. Dans notre exemple,
utiliser le constructeur de la classe parent était donc la bonne solution et c'est la
méthode habituelle : lors de la construction d'un objet fils, on appelle d'abord le
constructeur de l'objet parent puis on complète les initialisations propres cette fois
à l'objet fils (section dans notre exemple).
Tentons un premier programme de test :
using System;
public class test1{
public static void Main(){
Console.Out.WriteLine(new enseignant("Jean","Dupont",30,27).identite);
}
}
On voit que :
Soit un objet enseignant E. Cet objet contient en son sein un objet personne :
La propriété identité est définie à la fois dans la classe enseignant et sa classe mère
personne. Dans la classe fille enseignant, la propriété identite doit être précédée du
mot clé new pour indiquer qu'on redéfinit une nouvelle propriété identite pour la
classe enseignant.
public new string identite{
5.2.4. Le polymorphisme
Considérons une lignée de classes : C0→C1→C2→ … →Cn
où Ci→Cj indique que la classe Cj est dérivée de la classe Ci. Cela entraîne que la
classe Cj a toutes les caractéristiques de la classe Ci plus d'autres. Soient des objets
Oi de type Ci. Il est légal d'écrire :
Oi=Oj
fait que Oi est une référence à l'objet de type Ci contenu dans l'objet Oj.
Le mot clé virtual fait de identite une propriété virtuelle. Ce mot clé peut
s'appliquer également aux méthodes. Les classes filles qui
redéfinissent une propriété ou méthode virtuelle doivent utiliser alors le mot clé
override au lieu de new pour qualifier leur propriété/méthode redéfinie. Ainsi dans
la classe enseignant, la propriété identite est définie comme suit :
// surcharge propriété identité
on écrit implicitement :
public class personne : object
On remarquera que bien que nous n'ayons pas redéfini la méthode ToString dans les
classes personne et enseignant, on peut cependant constater que la méthode
ToString de la classe object est quand même capable d'afficher le nom réel de la
classe de l'objet.
Attardons-nous sur la méthode affiche qui admet pour paramètre une personne p.
Que signifie l'expression ""+p ? Le compilateur va ici chercher à transformet l'objet p
en string et cherche toujours pour cela l'existence d'une méthode appelée ToSTring.
Donc ""+p devient ""+p.Tostring(). La méthode ToString étant virtuelle, le compilateur
va exécuter la méthode ToString de l'objet réellement pointé par p.
op1 + op2
Où op1 et op2 sont deux opérandes. Il est possible de redéfinir le sens de l'opérateur
lorsque l'opérande op1 est un objet de classe C1.
Il suffit pour cela de définir une méthode statique dans la classe C1 dont la signature
est la suivante :
op1 + op2
On peut redéfinir également les opérateurs unaires n'ayant qu'un seul opérande.
Ainsi si op1 est un objet de type C1, l'opération op1++ peut être redéfinie par une
méthode statique de la classe C1 :
Ce qui a été dit ici est vrai pour la plupart des opérateurs avec cependant
quelques exceptions :
5.3.2. Un exemple
On crée une classe listeDePersonnes dérivée de la classe ArrayList. Cette
classe implémente un tableau dynamique et est présentée dans le chapitre qui
suit. De cette classe, nous n'utilisons que les éléments suivants :
int i;
// on parcourt le tableau dynamique
for (i=0;i<Count-1;i++){
liste+="["+base[i]+"]"+",";
}//for
// dernier élémenr
if(Count!=0) liste+="["+base[i]+"]";
liste+=")";
return liste;
}//ToString
public static void Main(){
// une liste de personnes
listeDePersonnes l=new listeDePersonnes();
// ajout de personnes
l=l+new personne("jean",10)+new personne("pauline",12);
// affichage
Console.Out.WriteLine("l="+l);
l=l+new personne ("tintin",27);
Console.Out.WriteLine("l="+l);
}//Main
}//class
Base de
Application I1 I2 données
Afin d'éviter qu'une application écrite pour une base de données B1 doive être
ré-écrite si on migre vers une base de données B2 différente, un effort de
normalisation a été fait sur l'interface I1. Si on utilise des bases de données utilisant
des pilotes "normalisés", la base B1 sera fournie avec un pilote P1, la base B2 avec
un pilote P2, et l'interface I1 de ces deux pilotes sera identique. Aussi n'aura-t-on
pas à ré-écrire l'application. On pourra ainsi, par exemple, migrer une base de
données ACCESS vers une base de données MySQL sans changer l'application.
Les pilotes ODBC permettent l'accès à des bases de données. Les sources de
données pour les pilotes OLE DB sont plus variées : bases de données, messageries,
annuaires, ... Il n'y a pas de limite. Toute source de données peut faire l'objet d'un
pilote Ole DB si un éditeur le décide. L'intérêt est évidemment grand : on a un accès
uniforme à une grande variété de données.
La plate-forme .NET est livrée avec deux types de classes d'accès aux données :
Les premières classes permettent un accès direct au SGBD SQL Server de Microsoft
sans pilote intermédiaire. Les secondes permettent l'accès aux sources de données
OLE DB.
La plate-forme .NET est fournie (mai 2002) avec trois pilotes OLE DB pour
respectivement : SQL Server, Oracle et Microsoft Jet (Access). Si on veut travailler
avec une base de données ayant un pilote ODBC mais pas de pilote OLE DB, on ne
peut pas. Ainsi on ne peut pas travailler avec le SGBD MySQL qui (mai 2002) ne
fournit pas de pilote OLE DB. Il existe cependant une série de classes permettant
l'accès aux sources de données ODBC, les classes odbc.net. Elles ne sont pas livrées
en standard avec le SDK et il faut aller les chercher sur le site de Microsoft. Dans
les exemples qui vont suivre, nous utiliserons surtout ces classes ODBC car la
plupart des bases de données sous Windows sont livrées avec un tel pilote.
1. mode connecté
2. mode déconnecté
3. ferme la connexion
3. ferme la connexion
5. lorsque le travail est fini, ouvre une connexion, envoie les données modifiées à la
source de données pour qu'elle les prenne en compte, ferme la connexion
Dans les deux cas, c'est l'opération d'exploitation et de mise à jour des données
qui prend du temps. Imaginons que ces mises à jour soient faites par un utilisateur
faisant des saisies, cette opération peut prendre des dizaines de minutes. Pendant
tout ce temps, en mode connecté, la connexion avec la base est maintenue et les
modifications immédiatement répercutées. En mode déconnecté, il n'y a pas de
connexion à la base pendant la mise à jour des données. Les modifications sont
faites uniquement sur la copie mémoire. Elles sont répercutées sur la source de
données en une seule fois lorsque tout est terminé.
• Si les données doivent circuler sur le réseau, le mode déconnecté est à choisir. Il
permet d'avoir une photo des données dans un objet appelé dataset qui représente
une base de données à lui tout seul. Cet objet peut circuler sur le réseau entre
machines.
namespace Phigo
{
class Connexion
{
private static OleDbConnection connection = null;
private static string chaine = @"Provider=Microsoft.ACE.OLEDB.12.0; Data
Source=ressources/inscription.accdb";
La classe Contrôle
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Phigo
{
public abstract class IControl <T>
{
public abstract bool create(T objet);
public abstract bool update(T objet);
public abstract bool delete(Object obj);
public abstract T find(Object obj);
}
}
namespace Phigo
{
public abstract class Personne
{
protected string nom;
protected string postnom;
protected string prenom;
protected string date;
protected string genre;
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) P a g e | - 32 -
public Personne() { }
public Personne(string nom, string postnom, string prenom, string date, string
genre)
{
this._nom = nom;
this._postNom = postnom;
this._prenom = prenom;
this._date = date;
this._genre = genre;
}
public string _nom
{
get { return this.nom; }
set { this.nom = value; }
}
public string _postNom
{
get { return this.postnom; }
set { this.postnom=value; }
}
public string _prenom
{
get { return this.prenom; }
set { this.prenom=value;}
}
public string _date
{
get { return this.date; }
set { this.date = value; }
}
public string _genre
{
get { return this.genre; }
set { this.genre = value; }
}
}
}
namespace Phigo
{
class Etudiant:Personne
{
private string matricule;
private int idPromotion;
public Etudiant() { }
public Etudiant( string matricule,
int idPromotion,
string nom,
string postnom,
string prenom,
string date,
string genre):base(
nom,
postnom,
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) P a g e | - 33 -
prenom,
date, genre)
{
this._matricule = matricule;
this._idPromotion = idPromotion;
}
public string _matricule
{
get { return this.matricule; }
set { this.matricule = value; }
}
public int _idPromotion
{
get { return this.idPromotion; }
set { this.idPromotion = value; }
}
}
}
namespace Phigo
{
class PersonneDAL:IControl<Etudiant>
{
private OleDbConnection connexion = null;
private OleDbCommand command = null;
//private OleDbDataReader reader = null;
private OleDbDataAdapter adapter = null;
private string sql;
private DataSet dataSet;
public override bool create(Etudiant objet)
{
connexion = Connexion.getConnexion();
try
{
connexion.Open();
sql = string.Format("Insert into Etudiant values
('{0}','{1}','{2}','{3}','{4}','{5}',{6})",objet._matricule,objet._prenom,objet._nom,obj
et._postNom,objet._date,objet._genre,objet._idPromotion);
command = new OleDbCommand(sql, connexion);
command.ExecuteNonQuery();
MessageBox.Show("succes","succes",MessageBoxButtons.OK,MessageBoxIcon.Information);
}
catch (Exception ee)
{
MessageBox.Show("Erreur:
"+ee.Message,"Erreur",MessageBoxButtons.OK,MessageBoxIcon.Warning);
}
finally {
if (connexion != null)
Ass. Ir. Philippe NKAYA
POO2 AVEC C# (SUITE) P a g e | - 34 -
connexion.Close();
}
return true;
}