Site:  Cours VB.net  
5.7 Composition, groupe d'objets.

Est-il possible mettre un objet dans un autre?

On a souvent besoin d'utiliser un ensemble, un groupe d'objets. Comment faire?

 

Un Objet dans un autre: Composition d'objets:

On parle de contenant-contenu.

On peut créer une Classe qui contient des Objets, une classe qui se compose d'objets.

 

Exemple classique:

Créons une Classe Point.

Class Point

Private _x As Integer

Private _y As Integer

Public Sub New(ByVal x As Integer, y As Integer)
          _x=x

          _y=y
End Sub

...

End Class

On a écrit uniquement le constructeur, il faudrait aussi écrire les property permettant de lire et écrire les coordonnées du point.

 

Maintenant on a besoin de créer une Classe rectangle qui est définie par 2 points (le coin supérieur gauche et le coin inférieur droit):

Class Rectangle

Private _p1 As Point

Private _p2 As Point

Public Sub New(ByVal x1 As Integer, ByVal y1 As Integer,ByVal x2 As Integer, ByVal y2 As Integer)
          _p1= New Point (x1,y1)

          _p2= New Point (x2,y2)
End Sub

...

End Class

 

Et bien, on utilise la classe Point dans la Classe Rectangle. le constructeur de la classe rectangle instancie 2 points, ce qui appelle le constructeur de la Classe Point.

 

Groupe d'objets:

 

Exemple: créons une Classe 'Salarié' avec une Property Nom et un constructeur New nécessitant un nom.

Public Class Salarié

Private _sNom As String

Public Property Nom() As String
          Get
               Nom = _sNom
          End Get
          Set
               _sNom = Value
          End Set
     End Property


Public Sub New(ByVal sNom As String)
          Nom = sNom
End Sub

 

End Class

 

Ensuite pour travailler sur un ensemble de salariés on peut:

A- Utiliser un tableau ou une collection de Salariés (pas bien !!)

B- Créer une Classe contenant des Salariés (good!)

 

A -Comment utiliser un tableau  ou une collection d'objets 'Salarié':

 

Voyons comment faire avec une approche non objet:

Dim LesSalaries(100)  As  Salarié

Attention, cela crée un tableau de références d'objet, mais pas les objets (Salariées(1) contient Nothing).

Il faut donc créer les objets:

LesSalaries(0) = New Salarié("toto")

LesSalaries(1) = New Salarié("lulu")

LesSalaries(2) = New Salarié("tata")

..

 

On peut ensuite utiliser  LesSalaries(1).Nom pour connaître le nom du salarié d'index 1.

 

Dim LesSalaries As New ArrayList  'On crée une collection d'objet ArrayList

Dim s As New Salarié("toto")      'On crée un Salarié

LesSalaries.Add (s)               'On l'ajoute dans l'Arraylist

 

LesSalariées.Count   retourne 1

 

Pour afficher dans une MsgBox  le nom du Salarié d'index 1:

 

MsgBox(CType(LesSalaries.Item(0), Salarié).Nom)

On remarque que LesSalaries.Item(0) est de type Objet (Les éléments d'un ArrayList sont des objets; Salaries.Item(0).GetType.BaseType.ToString retourne 'Objet') il faut donc caster en 'Salarié' à l'aide de CType:

CType(LesSalaries.Item(0), Salarié) ensuite , on peut utiliser .Nom

En Vb2005 (Framework 2):

On peut utiliser des collections 'génériques'

Dim LesSalaries As New System.Collections.Generic.List(Of Salarié)

On peut ainsi créer une collection fortement typée de 'Salarié'.

Mais utiliser un tableau ou une collection d'objets directement accessibles n'est pas une bonne méthode.

La bonne méthode est de créer une classe qui encapsule la collection (Une Classe qui contient la collection). Voyons donc la suite.

 

 

B -Utiliser Une Classe contenant des Salariés:

 

Voyons comment faire avec une approche objet:

 

Il faut créer une classe 'LesSalariés' contenant:

-un tableau ou une collection 'Private' complètement encapsulé, donc non accessible à l'extérieur.

-les méthodes 'Public' permettant d'avoir accès au données et de les modifier.

 

Il y a 4 manières de faire:

 

1-Créer une Classe contenant une ArrayList

 

Voyons un exemple utilisant une ArrayList (collection d'objets):

L'arrayList est créée par le constructeur.

Noter l'encapsulation:

 une méthode Add permet d'ajouter un 'Salarié' aux 'Salariés' (vu du coté utilisateur).

 La méthode Remove permet d'enlever un Salarié.

 Dans la classe une méthode Add permet d'ajouter un 'Salarié' à l'ArrayList.

 La Property Item permet de retourner un Salarié d'index lIndex.

 La Property Count retourne le nombre de Salarié.

 

Imports System.Collections

Public Class LesSalariésClasse
     Private maCol As ArrayList

     Public Sub New()
          maCol = New ArrayList()   
'cela crée une ArrayList
     End Sub

     Public Function GetEnumerator() As IEnumerator   
'permet d'utiliser For Each
          GetEnumerator = maCol.GetEnumerator
     End Function

     Public Function Add(ByVal LeNom As String) As Salarié
          Dim UnSalarié As New Salarié(LeNom)
          maCol.Add(UnSalarié)
          Add = UnSalarié
     End Function

      Public ReadOnly Property Item(ByVal lIndex As Integer) As Salarié
          Get
               Item = (CType(maCol.Item(lIndex),Salarié)
          End Get
     End Property

      Public ReadOnly Property Count() As Integer
          Get
               Count = maCol.Count
          End Get
     End Property

      Public Sub Remove(ByVal Key As String)
          maCol.Remove(Key)
     End Sub
End Class

 

Pour utiliser la Classe:

Dim LesSalariés As New LesSalariésClasse() 'création

LesSalariés.Add("Philippe")    'Ajout d'un salarié

LesSalariés.Count retourne 1   'connaître le nombre de salariés

Pour afficher le nom du premier salarié dans une MessageBox:

MsgBox(LesSalariés.Item(0).Nom)

 

Bien sur on peut utiliser une boucle For Each pour avoir accès à l'ensemble des salariés.

 

2-Créer une Classe héritant de la Classe ArrayList

On crée une classe héritant de ArrayList, ensuite on va créer une méthode Add pour ajouter un Salarié et une Property permettant de lire le nom du salarié d'index i; comme il existe déjà les membres Add et Index avec la même signature dans la classe parente, il faut remplacer ces membres, on le fait grâce à 'Shadows'.

Dans les nouveaux membres, on appelle les membres de la classe mère (grâce à MyBase)

Imports System.Collections

Public Class Salariés
     Inherits ArrayList

    
     Public  Shadows Sub Add(ByVal S As Salarié)
          MyBase.Add(S)
     End Function

      Public Shadows ReadOnly Property Index(ByVal i As Integer) As Salarié
          Get
               Return Ctype (MyBase.Item(i), Salarié)
          End Get
     End Property

     
End Class

Là aussi, les éléments d'un ArrayList sont des objets; il faut donc caster en 'Salarié' à l'aide de CType l'Item de l'ArrayList:

 

Dans l'exemple, on a utilisé une ArrayList, il est possible d'utiliser tout autre type de collections.

 

3-Créer une Classe héritant de la Classe CollectionBase

CollectionBase est une classe abstraite (ne pouvant pas être utilisée telle quelle), on peut créer une classe qui en hérite.

Cela tombe bien: CollectionBase contient déjà quelques fonctions propres aux collections (Clear et Count), les fonctions qui manquent, qui n'existent pas (Add, Remove, Item) vont être implémentées par vous et à votre manière.

Une propriété Protected appelée List est fournit par CollectionBase et utilisée pour le stockage et l'organisation interne. Quand on crée Add, Remove, Item, on utilise cette propriété List.  

 

Public Class MaCollection
Inherits System.Collections.CollectionBase

Public Sub Add(ByVal a As Salarié)
' Appelle la méthode Add de l'objet List pour ajouter un salarié.
List.Add(a)
End Sub

End Class

 

Remarquons que, bien que l'objet List soit non typé, cette méthode interdit l'ajout de tous les objets n'appartenant pas aux type Salarié. Alors que CollectionBase n'était pas typée, MaCollection est fortement typée car n'acceptant que des 'Salarié'.

On peut aussi ajouter une méthode éliminant un objet de la collection:

Public Sub Remove(ByVal index as Integer)
' Controle.
If index > Count - 1 Or index < 0 Then
    System.Windows.Forms.MessageBox.Show("Index non  valide!")
Else
' Appelle la méthode RemoveAt de l'objet List.
List.RemoveAt(index)
End If
End Sub

 

On peut enfin ajouter Item:

Public ReadOnly Property Item(ByVal index as Integer) As Salarié

Get
 Return CType(List.Item(index), Salarié)
End Get

End Property
 

Avec le Framework 2, il est possible d'utiliser, au leu de ListArray, une collection générique fortement typée: System.Collections.Generic.List(Of Salarié) 

 

4-Créer une Classe contenant une Classe générique

C'est possible avec le Framework 2

Au lieu de créer une ArrayList dans la Classe, on peut créer une collection générique (System.Collections.Generic) et lui imposer un type.

Ici on va créer une collection de salariés.

Imports System.Collections

Public Class LesSalariésClasse
     Private maCol As
System.Collections.Generic.List(Of Salarié)

     Public Sub New()
          maCol = New
System.Collections.Generic.List(Of Salarié)    'cela crée une Collection de salarié
     End Sub

     
     Public Function Add(ByVal Sal As Salarié)
          maCol.Add(Sal)
          Add = Sal
     End Function

     Public ReadOnly Property Item(ByVal lIndex As Integer) As Salarié
          Get
               Item = maCol.Item(lIndex)
 'On a directement un Objet Salarié: pas besoin de CType
          End Get
     End Property
...

End Class

 

On peut aussi créer des Stack(Of..) Queue(Of..), Dictionnary(Of..) SortedList(Of..)..

 

Cette méthode utilisant une collection d'objets complètement encapsulés est une bonne méthode.

 

Conclusion:

Si une classe doit contenir des objets:

Si vous ne voulez pas que des applications clientes puissent utiliser les objets contenus, définissez ces objets comme Friend ou Private