Ce cours présente les relations de composition et d'agrégation qu'il est possible d'établir entre plusieurs classes et objets. La seconde partie présente la notion d'immuabilité d'objets et montre comment faire des copies d'objets.
1. PO3T Programmation orientée objet
Séance 2
Composition, agrégation
et immuabilité
Sébastien Combéfis, Quentin Lurkin lundi 21 septembre 2015
2. Ce(tte) œuvre est mise à disposition selon les termes de la Licence Creative Commons
Attribution – Pas d’Utilisation Commerciale – Pas de Modification 4.0 International.
3. Rappels
Un objet est une instance d’une classe
État et vie de l’objet
Attributs et fonctionnalité
Une classe est un modèle à partir duquel on crée des instances
Variable et méthode d’instance
Constructeur et instanciation
Encapsulation de données
3
4. Objectifs
Relations possibles entre objets et classes
Composition et agrégation
Relation has-a
Objets immuables
Données non modifiables
Copie d’objets (shallow et deep)
4
6. Relation entre classes
Une classe définit un nouveau type de donnée
On peut l’utiliser pour définir des objets de ce type
Plusieurs classes peuvent être liées entre elle
Plusieurs types de relation sont possibles entre classes
Création de dépendances entre classes
Et donc entre les instances de ces classes
6
7. Représentation d’un dé
1 public class Die
2 {
3 public readonly int nbFaces;
4 private int visibleFace;
5 private static Random generator = new Random ();
6
7 public int VisibleFace {
8 get { return visibleFace; }
9 }
10
11 public Die () : this (6){}
12
13 public Die (int faces)
14 {
15 nbFaces = faces;
16 Roll ();
17 }
18
19 public void Roll ()
20 {
21 visibleFace = generator.Next (nbFaces) + 1;
22 }
23 }
7
9. Et en Java...
1 public class Die
2 {
3 public final int nbFaces;
4 private int visibleFace;
5
6 public Die ()
7 {
8 this (6);
9 }
10
11 public Die (int faces)
12 {
13 nbFaces = faces;
14 roll ();
15 }
16
17 public int getVisibleFace ()
18 {
19 return visibleFace ;
20 }
21
22 public void roll ()
23 {
24 visibleFace = (int) (Math.random () * nbFaces) + 1;
25 }
26 } 9
10. Création de dés
1 public static void Main (string [] args)
2 {
3 Die d1 = new Die ();
4 Die d2 = new Die (12);
5
6 Console .WriteLine (d1. VisibleFace );
7 Console .WriteLine (d2. VisibleFace );
8 }
d1
Die
Die
6
nbFaces
int
3
visibleFace
int
d2
Die
Die
12
nbFaces
int
7
visibleFace
int
Die
- int nbFaces
- int visibleFace
10
11. Qualité de code
Quid des variables d’instance publiques ?
3 public readonly int nbFaces;
Est-ce bien de réutiliser un constructeur ?
11 public Die () : this (6) {}
11
12. Représentation d’une paire de dés (1)
1 public class PairOfDice
2 {
3 private readonly int nbFaces;
4 private int visibleFace1 , visibleFace2 ;
5 private static Random generator = new Random ();
6
7 public PairOfDice(int faces)
8 {
9 nbFaces = faces;
10 visibleFace1 = generator.Next (nbFaces) + 1;
11 visibleFace2 = generator.Next (nbFaces) + 1;
12 }
13
14 public void PrintFaces ()
15 {
16 Console .WriteLine (String.Format ("{0}, {1}", visibleFace1 ,
visibleFace2 ));
17 }
18 }
12
13. Composition de classes
Définir une nouvelle classe à partir d’autres
En déclarant des variables d’instance des types utilisés
Éviter la répétition de code inutile
Facilite les corrections et les évolutions
Construire des objets à partir de blocs simples
Comme on le fait dans la vraie vie...
13
14. Représentation d’une paire de dés (2)
Un objet PairOfDice est composé à partir de deux objets Die
On déclare deux variables d’instance de type Die
1 public class PairOfDice
2 {
3 private int nbFaces;
4 private Die die1 , die2;
5
6 public PairOfDice(int faces)
7 {
8 nbFaces = faces;
9 die1 = new Die (faces);
10 die2 = new Die (faces);
11 }
12
13 public void PrintFaces ()
14 {
15 Console .WriteLine (String.Format ("{0}, {1}", die1.
VisibleFace , die2. VisibleFace ));
16 }
17 }
14
15. Relation de composition
Une classe A est composée à partir d’une classe B
Une instance de A a des variables d’instance de type B
Également appelée relation has-a
Une instance de A has-a B
PairOfDice Die
2
15
16. Une paire de dés
1 PairOfDice dice = new PairOfDice (6);
2 dice.PrintFaces (); // 1, 3
dice
PairOfDice
PairOfDice
6
nbFaces
int
die1
Die
die2
Die
Die
6
nbFaces
int
1
visibleFace
int
Die
6
nbFaces
int
3
visibleFace
int
16
17. Lien fort entre les instances composées
Instances composées fortement liées à l’instance de base
Elles disparaissent de la mémoire avec l’instance de base
Instances composées créées en même temps que celle de base
Lors de l’initiation de l’instance de base
17
18. Agrégation (1)
Généralisation de la composition, sans l’appartenance
Deux objets indépendamment créés vont pouvoir être agrégés
1 public class City
2 {
3 private Citizen mayor; // Bourgmestre de la ville
4 private String name; // Nom de la ville
5
6 public City ( String s)
7 {
8 name = s;
9 }
10
11 public void setMayor (Citizen c)
12 {
13 mayor = c;
14 }
15 }
18
19. Agrégation (2)
Généralisation de la composition, sans l’appartenance
Deux objets indépendamment créés vont pouvoir être agrégés
Suppression de l’instance de base sans toucher aux composées
1 Citizen philippe = new Citizen ("Philippe", "Melotte");
2
3 City woluwe = new City ("Woluwé -Saint -Lambert");
4 woluwe.setMayor (philippe);
City Citizen
0..1
19
20. Relation uses
Relation d’utilisation entre deux classes
Beaucoup plus générale que composition et agrégation
Recevoir un objet en paramètre ou renvoyer un objet
Voire même utiliser un objet dans le corps d’une méthode
Die Random
20
21. Couplage et cohésion
Classes couplées si l’une dépend de l’implémentation de l’autre
Une classe accède aux variables d’instance de l’autre...
Cohésion d’une classe mesure son niveau d’indépendance
Classe cohérente facilement maintenable et réutilisable
Il faut minimiser le couplage et maximiser la cohésion
21
23. Objet immuable
Un objet est immuable si son état ne peut être changé
Après avoir été initialisé par le constructeur
Pouvoir partager une référence vers un objet de manière sure
Sans risquer de voir l’état de l’objet modifié
Variables d’instance constantes ne suffit pas...
23
24. Représenter des coordonnées du plan
1 public class Point
2 {
3 private readonly int x, y;
4
5 public int X {
6 get { return x; }
7 }
8 public int Y {
9 get { return y; }
10 }
11
12 public Point (int x, int y)
13 {
14 this.x = x;
15 this.y = y;
16 }
17
18 public override string ToString ()
19 {
20 return String.Format ("({0} , {1})", x, y);
21 }
22 }
24
25. Représenter un vol d’avion (1)
1 public class Flight
2 {
3 private readonly string name;
4 private readonly List <string > passengers;
5
6 public List <string > Passengers {
7 get { return passengers; }
8 }
9
10 public Flight (string name)
11 {
12 this.name = name;
13 passengers = new List <string >();
14 }
15
16 public void AddPassenger (string name)
17 {
18 if (! passengers.Contains (name))
19 {
20 passengers.Add (name);
21 }
22 }
23 }
25
26. Valeur de retour de type objet
Une méthode renvoie une référence vers un objet
L’objet doit être copié pour maintenir l’immuabilité
1 Flight flight = new Flight ("UA 999");
2 flight. AddPassenger ("Clémence Flemal");
3 flight. AddPassenger ("Francis Gueuning");
4
5 Console .WriteLine (flight.Name);
6 Console .WriteLine (String.Join("n", flight.Passengers));
7
8 List <string > passengers = flight.Passengers;
9 passengers.Clear ();
10
11 Console .WriteLine (String.Join("n", flight.Passengers));
UA 999
Clémence Flemal
Francis Gueuning
26
27. Représenter un vol d’avion (2)
1 public class Flight
2 {
3 private readonly string name;
4 private readonly List <string > passengers;
5
6 public string Name {
7 get { return name; }
8 }
9
10 public Flight (string name , List <string > passengers)
11 {
12 this.name = name;
13 this.passengers = passengers;
14 }
15
16 public void AddPassenger (string name)
17 {
18 if (! passengers.Contains (name))
19 {
20 passengers.Add (name);
21 }
22 }
23 }
27
28. Paramètre de type objet
Une méthode qui reçoit un paramètre de type objet
L’objet doit être copié pour maintenir l’immuabilité
1 List <string > passengers = new List <string >();
2 passengers.Add ("Clémence Flemal");
3 passengers.Add ("Francis Gueuning");
4
5 Flight flight = new Flight ("UA 999", passengers);
6
7 Console .WriteLine (flight.Name);
8 Console .WriteLine (String.Join("n", flight.Passengers));
9
10 passengers.Clear ();
11
12 Console .WriteLine (String.Join("n", flight.Passengers));
UA 999
Clémence Flemal
Francis Gueuning
28
29. Représenter un rectangle
Les objets de type Rectangle sont-ils immuables ?
Oui ou non, justifier
1 public class Rectangle
2 {
3 private readonly Point lowerleft;
4 private readonly double width , height;
5
6 public Point LowerLeft { get { return lowerleft; } }
7 public double Width { get { return width; } }
8 public double Height { get { return height; } }
9
10 public Rectangle (Point corner , double width , double height)
11 {
12 lowerleft = corner;
13 this.width = width;
14 this.height = height;
15 }
16 }
29
30. Alias
Une copie d’une référence est un alias
Plusieurs variables qui permettent d’accéder au même objet
1 a = [1, 2, 3, 4, 5]
2 b = a
3 b[0] = 42
4 print(a) # [42, 2, 3, 4, 5]
5
6 b.append (9)
7 print(a) # [42, 2, 3, 4, 5, 9]
a
b
0 1 2 3 4
1 2 3 4 5
30
31. Copie de surface (1)
Copie d’un objet avec le module copy
La fonction copy fait une copie de surface
1 from copy import copy
2
3 a = [1, 2, 3, 4, 5]
4 b = copy(a)
5 b[0] = 42
6 print(a, b)
7
8 b.append (9)
9 print(a, b)
[1, 2, 3, 4, 5] [42, 2, 3, 4, 5]
[1, 2, 3, 4, 5] [42, 2, 3, 4, 5, 9]
31
32. Copie de surface (2)
Une copie de surface copie les références des objets
Suffisante si les objets contenus dans l’objet sont immuables
1 from copy import copy
2
3 a = [[1, 2], [3, 4, 5]]
4 b = copy(a)
5 b[0][1] = 42
6 print(a, b) # [[1, 42], [3, 4, 5]] [[1, 42], [3, 4, 5]]
7
8 b[1] = [42]
9 print(a, b) # [[1, 42], [3, 4, 5]] [[1, 42], [42]]
a
0 1
0
3
1
4
2
5
0
1
1
2
32
33. Copie en profondeur
Copie d’un objet avec le module copy
La fonction deepcopy fait une copie en prodonfeur
1 from copy import deepcopy
2
3 a = [[1, 2], [3, 4, 5]]
4 b = deepcopy (a)
5 b[0][1] = 42
6 print(a, b)
7
8 b[1] = [42]
9 print(a, b)
[[1, 2], [3, 4, 5]] [[1, 42], [3, 4, 5]]
[[1, 2], [3, 4, 5]] [[1, 42], [42]]
33