Introduction
Le language PL/SQL met à la disposition du développeur des procédures et des fonctions ainsi que des packages pour les encapsuler. Les défauts de ce mode de programmation sont identiques à ceux rencontrés avec n'importe quel langage procédural:
- code spaghetti
- difficulté de maintenance
Pour palier ces différents problèmes, le paradigme objet a été introduit à travers les types.
Le projet: notifications par mail.
Pour introduire les différents concepts de la programmation orienté objet au langage PL/SQL, nous implémentons un modèle permettant l'envoi de mail avec un contenu de type texte et/ou d'un tableau (formatage automatique des colonnes).

- CONTENT: Une interface représentant le contenu de la notification,
- COMPOSITECONTENT: Un contenu composé d'autres contenus (texte, tableau ou composite),
- TEXTCONTENT: Un contenu textuel pour le corps de l'e-mail,
- TABCONTENT: Un contenu sous forme de tableau,
- NOTIF: Une notification par e-mail.
Déclaration d'une classe
Une classe en PL/SQL est décrite comme étant un type. Sa structuration est semblable a celle d'un package PL/SQL, c'est-à-dire qu'il y a une partie concernant la déclaration des méthodes et une seconde partie, appelé le
body, qui implémente les méthodes.
Un constructeur par défaut (sans paramètres) est ajouté par le compilateur si la classe n'en définit pas.
Le type NOTIF est définit comme étant un objet en le déclarant:
AS OBJECT. Nous verrons par la suite comme définir un objet comme héritant d'un autre objet.
ATTENTION: Une contrainte sur la partie déclaration, celle-ci doit contenir au moins un attribut, que ce soit par héritage ou par déclaration propre.
CREATE TYPE NOTIF AS OBJECT
(
mailhost VARCHAR2(254),
to_address CHARLIST,
from_address VARCHAR2(254),
subject VARCHAR2(254),
MEMBER PROCEDURE send
);
/
CREATE TYPE BODY NOTIF AS
MEMBER PROCEDURE send IS
...
END send;
END;
/
En PL/SQL, il n'est pas possible de définir des méthodes ou des attributs privés ou protégés. Tout ce qui est définit dans un type est accessible dés qu'un objet est été créé.
Il également possible de définir des méthodes statiques, c'est-à-dire des méthodes définis pour le type et indépendante de l'instance d'objet. Pour déclarer une méthode statique, il suffit de remplacer le mot clé
MEMBER par
STATIC.Instanciation et appels de méthode
L'instanciation dans un nouvel objet ne se fait pas, contrairement à la plupart des langages orientés objets, par l'appel au mot clé
new. Celui-ci n'existe pas en PL/SQL. L'initialisation d'un nouvel objet se fait par l'appel au constructeur, comme s'il s'agissait d'une méthode définit dans un package standard. Dans notre cas, il s'agit du constructeur par défaut qui a été ajouté par le compilateur.
declare
n NOTIF;
begin
n := NOTIF();
....
end;
Pour les appels de méthode, le mécanisme implémenté est le même que dans la plupart des langages objet: la notation pointé.
declare
n NOTIF;
begin
n := NOTIF();
....
n.send;
end;L'appel d'une méthode statique ne nécessite pas la création d'une instance. Elle peut être appelée de la même façon que pour une méthode contenue dans un package:
nom_type.nom_methode(arguments...)Définition d'un constructeur
Nous allons maintenant définir un constructeur pour le type NOTIF. Celui-ci devra prendre en paramètre un objet de type CONTENT.
CREATE TYPE NOTIF AS OBJECT
(
CONSTRUCTOR FUNCTION NOTIF(c CONTENT) RETURN SELF AS RESULT
);
/
CREATE TYPE BODY NOTIF AS
CONSTRUCTOR FUNCTION NOTIF(c CONTENT) RETURN SELF AS RESULT AS
BEGIN
SELF.notif_content := c;
RETURN;
END NOTIF;
END;
/Le constructeur définit ci-dessus se présente sous la forme d'une fonction retournant
SELF comme résultat.
SELF est le mot clé définissant une référence à l'objet courant. La fonction doit également être déclarée comme étant un constructeur par l'utilisation du mot clé
CONSTRUCTOR. La fin de la méthode doit être indiqué par le mot clé
RETURN. Mais aucun objet ne doit être renvoyé.
REMARQUE: SELF étant une référence à l'objet courant, il peut être utilisé pour lever une ambiguïté. Par exemple, lorsqu'une variable locale a le même nom qu'une variable d'instance.
Définition d'une interface
Autant le dire, les interfaces n'existent pas en PL/SQL, mais il est possible de faire quelque chose qui s'en rapproche.
Dans notre exemple, le type CONTENT représente une interface, c'est-à-dire qu'il doit seulement contenir le prototype des méthodes, ne pas être instanciable et pouvoir être hérité. Puisque nous n'avons pas besoin de définir le corps des fonctions, nous n'avons pas besoin de définir le corps du type (partie BODY).
CREATE TYPE CONTENT AS OBJECT
(
text VARCHAR2(4000),
MEMBER FUNCTION format RETURN LONG
) NOT FINAL NOT INSTANTIABLE;
/
La variable d'instance
text a été définit pour respecter la syntaxe du langage: tout type doit avoir au moins un attribut, que ce soit par héritage ou qu'il le définisse lui même.
Par défaut, le PL/SQL n'autorise pas l'héritage d'un type. Pour l'autoriser, il faut rajouter à la fin de la déclaration du type:
NOT FINAL.Par défaut, il est autorisé d'instancier n'importe quel type. Pour empécher l'initialisation d'objets de type CONTENT, il faut ajouter à la fin de la déclaration du type:
NOT INSTANCIABLE.L'héritage et polymorphisme
Nous allons maintenant implémenter le type TEXTCONTENT chargée d'implémenter un texte simple. Ce type hérite de CONTENT:
CREATE TYPE TEXTCONTENT UNDER CONTENT
(
MEMBER PROCEDURE set_content(t VARCHAR2),
OVERRIDING MEMBER FUNCTION format RETURN LONG
);
/
CREATE TYPE BODY TEXTCONTENT AS
MEMBER PROCEDURE set_content(t VARCHAR2) IS
BEGIN
SELF.text := t;
END;
OVERRIDING MEMBER FUNCTION format RETURN LONG IS
BEGIN
RETURN SELF.text || chr(13) || chr(10);
END format;
END;
/
L'héritage est déclaré par le mot clé:
UNDER. Pour hériter d'un type, le type courant doit être déclaré:
CREATE TYPE TEXTCONTENT UNDER CONTENTau lieu de:
AS OBJECT.
Le PL/SQL ne supporte que l'héritage simple.
Pour redéfinir une méthode, celle-ci doit être déclarée avec le mot clé:
OVERRIDING.Il est possible de définir un méthode de façon à ce qu'elle ne puisse être redéfini en ajout le mot clé
FINAL devant la définition d'une méthode.
Le partage d'objet
Le PL/SQL implémente le passage de paramètre par copie, c'est-à-dire, qu'à chaque fois qu'une variable est affectée à un objet, celui-ci est copié dans une nouvelle instance. Toutefois, un mécanisme nous permet d'utiliser un passage de paramètre par référence. En utilisant le mot clé
REF devant le type de la variable, celle-ci peut alors partager un objet avec une autre variable.
Dans notre exemple, il faut donc ajouter
"REF" devant les attributs ayant pour type, ceux du projet de notification.
Conclusion
La programmation objet permet d'organiser son code de manière à ce que celui-ci puisse être plus facilement réutilisable. Alors pourquoi ne pas s'en servir en PL/SQL.
Le modèle objet proposé par le PL/SQL est relativement simple (pas d'héritage multiple, ni d'interface), mais il permet tout de même de résoudre des problèmes complexes avec élégance.
Références
Code SourceDocumentation Oracle