PureBasic
et la Programmation Orientée Objet
Implémentation des concepts
Dans ce qui va suivre, nous allons voir comment les concepts objets qui
viennent d'être abordés peuvent être implémentés
en PureBasic.
En aucun cas cela fait référence à ce qui est programmé
dans les langages objets. De plus, le propre de l'implémentation
c'est de pouvoir être amélioré ou de s'adapter au
besoin.
Nous proposons donc ici une de ces d'implémentations avec ses avantages
et ses limites.
Première Implémentation
Classe concrète
et Classe abstraite
Comme nous l'avons vu, la Classe définie ce que contient un objet:
- ses attributs (type de chaque variable)
- ses méthodes (noms, implémentation)
Si, par exemple, on veut représenter des objets Rectangle et les
afficher à l'écran, on définira donc une Classe Rectangle
possédant une méthode Dessiner().
La Classe Rectangle pourrait avoir la construction suivante:
Structure
Rectangle
*Dessiner
x1.l
x2.l
y1.l
y2.l
EndStructure
Procedure
Dessiner_Rectangle(*this.Rectangle)
EndProcedure
|
où x1, x2, y1 et y2 sont quatre attributs (les coordonnées
des points diamétralement opposés du rectangle) et *Dessiner
est un pointeur faisant référence à la fonction de
dessin qui affiche les Rectangles.
*Dessiner est ici un pointeur de fonction utilisé pour contenir
l'adresse de la fonction désirée : @Dessiner_Rectangle().
Il suffit d'utiliser CallFunctionFast() pour lancer l'exécution
de la fonction ainsi référencée.
Nous voyons donc que l'instruction Structure est tout à fait adaptée
à la notion de Classe:
Nous y trouvons la définition des attributs d'un objet : ici x1,
x2, y1 et y2 sont de type entier Long.
Nous y trouvons la définition des méthodes : ici Dessiner()
grâce à un pointeur de fonction.
Si la Classe ainsi définie est suivit de l'implémentation
des méthodes (dans notre exemple il s'agit de la déclaration
du bloc Procedire/EndProcedure de Dessiner_Rectangle()),
la Classe sera une Classe concrète.
Dans le cas contraire elle sera abstraite.
|
On appelle toujours *this, le pointeur vers
l'objet auquel on applique la méthode. Cette notation est appliquée
dans notre exemple avec la méthode Dessiner_Rectangle(). |
Instanciation
Si l'on désire créer maintenant un objet Rect1 issu de la
classe Rectangle, cela revient à écrire :
Pour l'initialiser, il suffit d'écrire :
Rect1\Dessiner = @Dessiner_Rectangle()
Rect1\x1 = 0
Rect1\x2 = 10
Rect1\y1 = 0
Rect1\y2 = 20
|
Par la suite, pour dessiner l'objet Rect1, on écrira:
CallFunctionFast(Rect1\Dessiner,
@Rect1)
|
Encapsulation
Dans cette implémentation, l'encapsulation n'existe pas, tout simplement
car il n'y a pas moyen de cacher les attributs ou les méthodes
d'un tel objet.
En effet, il suffit d'écrire Rect1\x1 pour accéder à
l'attribut x1 de l'objet. C'est d'ailleurs ce moyen que nous avons utilisé
pour initialiser l'objet.
Nous verrons dans la deuxième implémentation, comment cela
peut changer.
Cependant, cette notion, bien qu'important, n'est pas la plus essentielle
pour faire de la POO.
Héritage
Imaginons maintenant que l'on souhaite créer une nouvelle Classe
d'objet Rectangle capable en plus de s'effacer de l'écran.
On peut se servir de la Classe existante Rectangle et y adjoindre la nouvelle
méthode Effacer() pour créer
la nouvelle Classe Rectangle2
Une Classe étant une Structure, nous allons profiter de la propriété
qu'a une structure d'être étendue. Ainsi, la nouvelle Classe
Rectangle2 peut s'écrire :
Structure Rectangle2 Extends
Rectangle
*Effacer
EndStructure
Procedure Effacer_Rectangle(*this.Rectangle2)
EndProcedure
|
La Classe Rectangle2 possède donc bien les membres de la Classe
Rectangle et une nouvelle méthode Effacer().
En effet, l'instanciation d'un objet de cette Classe donne :
Rect2.Rectangle2
Rect2\Dessiner = @Dessiner_Rectangle()
Rect2\Effacer = @Effacer_Rectangle()
Rect2\x1 = 0
Rect2\x2 = 10
Rect2\y1 = 0
Rect2\y2 = 20
|
Pour utiliser les méthodes Dessiner()
et Effacer() de Rect2, on procèdera
de la même manière que précédemment.
Nous pouvons donc dire que Rectangle2 a hérité des propriétés
de la Classe Rectangle.
|
L'héritage est une forme de polymorphisme.
L'objet Rect2 peut etre vu comme un Objet de la Classe Rectangle,
il suffit de ne pas se servir de la méthode Effacer(). Par
héritage, l'objet revête donc plusieurs formes : celles des
objets issus des différentes Classes Mères. On parle
alors de polymorphisme d'héritage. |
Surcharge
Lors de l'initialisation d'un objet, on initialise les pointeurs de fonction
en leur affectant l'adresse de la méthode qui convient à
l'objet.
Ainsi, pour un objet Rect de Classe Rectangle, en écrivant:
Rect1\Dessiner = @Dessiner_Rectangle()
|
on peut utiliser la méthode Dessiner()
comme suite:
CallFunctionFast(Rect1\Dessiner,
@Rect1)
|
Maintenant, imaginons qu'il soit possible d'implémenter une autre
méthode pour l'affichage d'un rectangle (utilisant un algorithme
distinct de celui de la premiere méthode).
Appelons la Dessiner_Rectangle2():
Procedure Dessiner_Rectangle2(*this.Rectangle)
EndProcedure
|
Il est tout à fait possible d'initialiser notre objet Rect1 avec
cette nouvelle méthode sans grande peine:
Rect1\Dessiner = @Dessiner_Rectangle2()
|
Si l'on veut utiliser la méthode on écrira à nouveau:
CallFunctionFast(Rect1\Dessiner,
@Rect1)
|
Nous constatons bien que dans un cas (méthode Dessiner_Rectangle())
comme dans l'autre (méthode Dessiner_Rectangle2())
l'utilisation de la méthode de l'objet Rect1 est strictement identique.
Il ne nous est pas possible en effet par la seule ligne "CallFunctionFast(Rect1\Dessiner,
@Rect1)"
de distinguer la méthode Dessiner()
que l'objet Rect1 utilise.
Pour y arriver, il faut remonter jusqu'à l'initialisation de l'objet.
La notion de pointeur de fonction permet donc la surcharge de la méthode
Dessiner() de la Classe Rectangle.
Il y a tout de même une limitation dans cette surcharge. L'utilisation
de l'instruction CallFunctionFast() implique de faire attention au nombre
de paramètres.
Conclusion :
Dans cette première implémentation, nous disposons d'un
objet capable de répondre aux principaux concepts orientés
objet avec certaines limitations.
Nous venons surtout de poser les bases qui vont nous servir à réaliser
un objet plus complet, ceci grâce à l'instruction Interface
de PureBasic.
[1-2-3-4-5-6-7-8-9]
Retour en haut de page
|