Précédent Index Suivant

Relations entre classes

Les classes d'une application peuvent entretenir entre elles deux types de relations.
  1. une relation d'agrégation, appellée Has-a .

    Une classe C2 est dans la relation Has-a avec une classe C1 si C2 possède un champs du type de C1. Cette relation se généralise en C2 possède au moins un champ du type de C1.
  2. relation d'héritage : Is-a.

    La classe C2 est sous-classe de la classe C1 lorsque C2 est obtenue par extension du comportement de C1. C'est l'avantage majeur de la programmation objet que de pouvoir étendre le comportement d'une classe existante tout en continuant à utiliser le code écrit pour la classe originale. Quand on étend une classe, la nouvelle classe hérite de tous les champs, de données et de méthodes, de la classe qu'elle étend.

Relation d'agrégation

Une classe c1 est en relation d'agrégation avec une classe c2, si au moins une de ses variables d'instance est de type c2. On indique l'arité de la relation quand elle est connue.

Exemple de relation d'agrégation

On définit une figure comme un ensemble de points. On déclare pour cela la classe picture (voir figure 2.2) dont un des champs est un tableau de points. La classe picture entretient donc la relation généralisée Has-a avec la classe point.

# class picture n =
object
val mutable ind = 0
val tab = Array.create n (new point(0,0))
method add p =
try tab.(ind)<-p ; ind <- ind + 1
with Invalid_argument("Array.set")
-> failwith ("picture.add:ind =" ^ (string_of_int ind))
method remove () = if (ind > 0) then ind <-ind-1
method to_string () =
let s = ref "["
in for i=0 to ind-1 do s:= !s ^ " " ^ tab.(i)#to_string() done ;
(!s) ^ "]"
end ;;
class picture :
int ->
object
val mutable ind : int
val tab : point array
method add : point -> unit
method remove : unit -> unit
method to_string : unit -> string
end
On construit une picture en lui ajoutant des points.

# let pic = new picture 8;;
val pic : picture = <obj>
# pic#add p1; pic#add p2; pic#add p3;;
- : unit = ()
# pic#to_string ();;
- : string = "[ ( 0, 0) ( 3, 4) ( 3, 0)]"


Notation graphique de l'agrégatation

La relation entre la classe picture et la classe point est représentée graphiquement par la figure 2.2. Une flèche, dont l'origine comporte un losange et l'extrémité forme une pointe vide, indique la relation d'agrégation.


Figure 2.2 : Relation d'agrégation


On indique par ailleurs au dessus de la flèche l'arité de la relation.

Relation d'héritage

C'est la relation essentielle de la programmation objet. Quand une classe c2 hérite d'une classe c1 elle récupère tous les champs de la classe ancêtre. Elle peut dont alors définir de nouveaux champs et même redéfinir des méthodes héritées pour les spécialiser. Comme la classe ancêtre n'a pas été modifiée, les applications s'en servant n'ont pas être adaptées aux changements apportés à la nouvelle classe.

La syntaxe de l'héritage indique le lien d'héritage d'une autre_classe en lui passant (si il y a lieu) les valeurs initiales pour la construction d'un objet d'autre_classe.

Syntaxe


inherit autre_classe e1 ... em [ as nom_ancetre ]
Il est possible d'associer un nom à la classe ancêtre pour accéder aux méthodes de celle-ci en cas de redéfinition d'une méthode dans la classe descendante (voir page X).

Exemple d'héritage simple

L'exemple classique est d'étendre la classe point en ajoutant un attribut de couleur aux points. On définit alors la classe colored_point qui hérite de la classe point. La couleur est représentée par le champ c de type string. On ajoute une méthode get_color qui retourne la valeur de ce champ. La conversion vers une chaîne de caractères doit alors tenir compte de cet attribut et sera donc redéfinie.

# class colored_point (x,y) c =
object
inherit point (x,y)
val mutable c = c
method get_color = c
method set_color nc = c <- nc
method to_string () = "( " ^ (string_of_int x) ^
", " ^ (string_of_int y) ^ ")" ^
" de couleur " ^ c
end ;;
class colored_point :
int * int ->
string ->
object
val mutable c : string
val mutable x : int
val mutable y : int
method distance : unit -> float
method get_color : string
method get_x : int
method get_y : int
method moveto : int * int -> unit
method rmoveto : int * int -> unit
method set_color : string -> unit
method to_string : unit -> string
end


Les valeurs initiales pour la construction d'un colored_point sont le couple de coordonnées nécessaire pour la construction d'un point et la couleur du point coloré.

L'ensemble des méthodes héritées ou nouvellement définies ou redéfinies correspond à l'ensemble des comportements des instances de la classe.

# let pc = new colored_point (2,3) "blanc";;
val pc : colored_point = <obj>
# pc#get_color;;
- : string = "blanc"
# pc#get_x;;
- : int = 2
# pc#to_string();;
- : string = "( 2, 3) de couleur blanc"
# pc#distance;;
- : unit -> float = <fun>
On dit que la classe point est la classe ancêtre de la classe colored_point et que celle-ci est la classe fille de celle-là.

Warning


La redéfinition d'une méthode par une classe fille doit respecter le type de la méthode définie dans la classe ancêtre.



Notation graphique de l'héritage

La relation d'héritage entre classes se note par une flèche, dont la pointe est formée par un triangle fermé, allant de la classe fille vers la classe ancêtre. Dans la représentation graphique de l'héritage, on ne fait figurer dans la classe fille que les nouveaux champs et méthodes et les méthodes redfinies. La figure 2.3 illustre la relation entre la classe colored_point et son ancêtre point.



Figure 2.3 : Relation d'héritage


Comme il contient des méthodes supplémentaires, le type colored_point est différent du type point. Le test d'égalité entre deux instances de ces classes provoque l'affichage d'un long message d'erreur qui rappelle le type complet de chaque classe pour bien montrer leur différence.

# p1 = pc;;
Characters 6-8:
This expression has type
colored_point =
< distance : unit -> float; get_color : string; get_x : int; get_y :
int; moveto : int * int -> unit; rmoveto : int * int -> unit;
set_color : string -> unit; to_string : unit -> string >
but is here used with type
point =
< distance : unit -> float; get_x : int; get_y : int;
moveto : int * int -> unit; rmoveto : int * int -> unit;
to_string : unit -> string >
Only the first object type has a method get_color



Précédent Index Suivant