novembre
2011
Dans le cadre d’une discussion j’ai été amené à faire une digression sur les dépendances entre les classes dans la programmation orientée objet.
A des fins d’éclaircissement, je vous propose donc un récapitulatif des quatre manières possibles de coupler deux classes entre-elles.
Les interfaces seront abordées ultérieurement.
Pour illustrer les propos, nous allons travailler sur un exemple parlant à tous : le corps humain, ses organes et ses accessoires.
A noter que le code d’exemple sera en PHP.
1. Aperçu rapide des couplages possibles avec la notation UML correspondante
La notation UML n’est qu’à titre de rappel, ce n’est pas le propos de cet article.
2. HERITAGE OU DERIVATION
De tous les liens possibles, c’est le plus fort. Le concept d’héritage s’insère dans une approche très pragmatique de notre environnement à savoir : la généricité et la spécialisation. L’héritage permet dans un sens la factorisation (généricité, abstraction) et dans l’autre, la spécialisation (héritage, dérivation) des classes. De ce lien découle une contrainte très forte à laquelle il est essentiel de s’y conformer : les classes dérivées doivent obligatoirement être de même nature que leur classe mère.
En clair, il doit être toujours possible de considérer que la classe dérivée est une classe mère spécialisée.
Pour un organisme cela donnerait par exemple ceci :
En conséquence, il est tout à fait possible de dire que la classe Poumon est une instance de la classe Organe. Les classes Rein et Estomac sont également des instances de la classe Organe.
Et voici le code PHP correspondant :
HERITAGE FONCTIONNEL : ATTENTION DANGER
L’héritage n’est qu’une forme de couplage parmi d’autres, dès que la contrainte sur la nature des classes mères et dérivées n’est plus respectée, il faut absolument changer la manière de coupler les classes entre elles. Dériver les classes n’importe comment – sans justifier d’un quelconque lien conceptuel – dans le but de récupérer les fonctions d’une classe est un abus sévère du concept d’héritage. Cette méthode s’appelle : héritage fonctionnel et est à proscrire.
L’erreur la plus courante consiste à dériver la classe d’accès aux données afin que le concept ainsi créé puisse accéder aux fonctions d’écriture, de lecture… de la base de données. En plus d’être une ineptie – conceptuellement parlant – cela dégrade grandement les performances parce que chaque instanciation de classe va probablement ouvrir une connexion avec la base de données, alors que généralement, une seule connexion suffit amplement.
Dans notre cas cela donnerait ceci :
Et voici le code PHP correspondant :
3. COMPOSITION
C’est un lien très fort entre les classes.
La composition définit par principe que les classes composites ne peuvent exister en dehors de la classe composée.
Le corollaire est que la destruction de la classe composée implique la destruction des classes composites.
Pour faire plus clair : le corps humain ne peut exister sans ses organes et réciproquement les organes ne peuvent exister en-dehors du corps humain.
Donc, la classe composée contrôle la totalité de la vie de ses composites (de leur naissance à leur mort), son constructeur doit se charger de les instancier et son destructeur de les détruire. L’accès aux composites est limité et toujours sous contrôle de la classe composée.
Pour un corps humain cela donnerait par exemple ceci :
Et voici le code PHP correspondant :
3. AGREGATION
C’est un lien fort entre les classes.
L’agrégation définit par principe que les classes agrégées ont une existance indépendante de la classe agrégat.
Généralement cela se traduit au sein de la classe agrégat : par le passage au constructeur des instances des classes à agréger ou par la définition de mutateurs avec des paramètres typés.
Ex : setPoumons(Poumon $poumon) { }
Pour suivre notre exemple, il faut se placer dans un futur proche dans lequel il serait possible de remplacer ses organes à la carte.
Cela impliquerait que les organes pourraient exister en dehors du corps humain qui ne ferait du coup que les agréger pour assurer son fonctionnement.
Pour un corps humain cela donnerait par exemple ceci :
Et voici le code PHP correspondant :
4. ASSOCIATION
C’est un lien faible entre les classes.
L’association se résume à un paramètre typé que l’on passe à une fonction d’une classe.
La classe qui exécute la fonction se sert du paramètre mais ne garde aucune trace de ce dernier.
Pour un corps humain cela donnerait par exemple ceci :
Et voici le code PHP correspondant :
5. CONCLUSION
Vous avez eu un aperçu des différents couplages possibles en programmation orientée objet. On pourrait encore en écrire beaucoup dessus.
A noter que la tendance actuelle est au découplage et à l’injection dynamique des dépendances afin de faciliter la portabilité et la maintenance des application.
Enfin un dernier point, notez que dans tous les cas, l’organisation et la décomposition de vos classes reste subjective.
Outre une compréhension exacte de la problématique, c’est un mélange de finesse et d’expérience.
Dans la plupart des cas, votre architecture sera discutable mais le plus important est de rester clair, concis et apte à justifier ses choix.
Un vrai travail de concepteur.
Attention toutefois, si vous commencez à tout séparer et hiérarchiser dans votre vie (copine, amis, collègues…), c’est qu’il est temps d’aller consulter…
Merci pour cette intéressante piqûre de rappel, c’est jamais inutile de revoir les fondamentaux. J’attends avec beaucoup d’intérêt un futur article sur les interfaces !