PO3T Programmation orientée objet
Séance 2
Composition, agrégation
et immuabilité
Sébastien Combéfis, Quentin Lurkin lundi 21 septembre 2015
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.
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
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
Composition
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
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
Et en Python...
1 from random import randint
2
3 class Die:
4 def __init__(self , faces =6):
5 self.__nbfaces = faces
6 self.roll ()
7
8 @property
9 def nbfaces(self):
10 return self.__nbfaces
11
12 @property
13 def visibleface(self):
14 return self. __visibleface
15
16 def roll(self):
17 self. __visibleface = randint (1, self.nbfaces)
8
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
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
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
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
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
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
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
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
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
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
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
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
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
Immuabilité
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
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
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
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
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
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
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
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
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
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
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
Crédits
https://www.flickr.com/photos/cameliatwu/6122062721
https://www.flickr.com/photos/jeffkrause/7192807880
34

Composition, agrégation et immuabilité

  • 1.
    PO3T Programmation orientéeobjet Séance 2 Composition, agrégation et immuabilité Sébastien Combéfis, Quentin Lurkin lundi 21 septembre 2015
  • 2.
    Ce(tte) œuvre estmise à disposition selon les termes de la Licence Creative Commons Attribution – Pas d’Utilisation Commerciale – Pas de Modification 4.0 International.
  • 3.
    Rappels Un objet estune 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 entreobjets et classes Composition et agrégation Relation has-a Objets immuables Données non modifiables Copie d’objets (shallow et deep) 4
  • 5.
  • 6.
    Relation entre classes Uneclasse 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é 1public 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
  • 8.
    Et en Python... 1from random import randint 2 3 class Die: 4 def __init__(self , faces =6): 5 self.__nbfaces = faces 6 self.roll () 7 8 @property 9 def nbfaces(self): 10 return self.__nbfaces 11 12 @property 13 def visibleface(self): 14 return self. __visibleface 15 16 def roll(self): 17 self. __visibleface = randint (1, self.nbfaces) 8
  • 9.
    Et en Java... 1public 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 1public 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 Quiddes 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 pairede 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éfinirune 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 pairede 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 Uneclasse 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 dedé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 entreles 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 dela 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 dela 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’utilisationentre 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 Classescouplé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
  • 22.
  • 23.
    Objet immuable Un objetest 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éesdu 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 vold’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 retourde 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 vold’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 typeobjet 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 Lesobjets 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’uneré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 Copied’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
  • 34.