Non. Avec l’objet tu peux structurer ton code pour le rendre bien plus facile à maintenir, faciliter le travail à plusieurs, le fiabiliser, etc… Tu ne pourras jamais arriver au même niveau sur ces points en 100% procédural.
Je vais te donner un exemple concret sur le côté « maintenabilité ».
Imagines que tu travailles en équipe sur une application. Il y a une partie de l’équipe qui travaille sur un système qui détecte des points sur un plan. Et on te demande à toi de faire une fonction qui prend l’ensemble de tous les points et renvoie pour chaque point celui qui est le plus proche.
Comment tu fais ça en procédural ?
Tu commences par demander à tes collègues comment ils représentent un point. Ce sera deux entiers. Ils te fournissent une fonction pour calculer la distance entre deux points. C’est donc une fonction qui va prendre 4 entiers en paramètre et en renvoyer un.
Toi tu dois faire une fonction qui prend en paramètre un nombre variable d’entiers (2 pour chaque point) et renvoie un nombre deux fois plus grand d’entiers (4 pour chaque couple point de référence/point le plus proche… pour simplifier, on part sur l’implémentation naïve où pour B le plus proche de A on va renvoyer à la fois AB et BA).
Donc, tu écris ta fonction (je le fait en pseudo langage français) :
calc_point_le_plus_proche(int[] coordonnees):
__nb_points = taille(coordonnees) / 2
__resultat = int[nb_points * 2]
__pour i de 0 a nb_points - 1:
____resultat[4i] = x = coordonnees[2i]
____resultat[4j] = y = coordonnees[2i+1]
____distance_min = -1
____pour j de 0 a nb_points - 1 et j != i
______x_a_tester = coordonnees[2j]
______y_a_tester = coordonnees[2j+1]
______distance_a_tester = calc_distance(x, y, x_a_tester, y_a_tester)
______si distance_min == -1 ou distance_min < distance_a_tester:
________resultat[4i+2] = x_a_tester
________resultat[4j+3] = y_a_tester
________distance_min = distance_a_tester
__retourne resultat
Bien entendu, tu peux le découper en sous-fonctions, mais ça ne changera rien à la maintenabilité du code.
Bon, tu as fini, tu as testé, t’es content, tout marche nickel. Tu le dit aux collègues. À merde, on a oublié de te dire, finalement on travaille dans l’espace, pas dans le plan, donc 3 entiers pour un point, voilà la nouvelle fonction pour calculer les distances.
Et hop, tu dois retravailler tout ton code, pour introduire une coordonnée z, adapter les index des array en conséquence (on saute désormais de 3 en 3 dans l’entrée, de 6 en 6 pour la sortie…), etc… Tu le fait, 2 jours plus tard les collègues reviennent, « bon, on a deux appareils d’acquisition différents, y en a un qui nous renvoie des coordonnées en cartésien, l’autre en polaire… alors on a ajouté un entier pour dire si le point suivant est en polaire ou en cartesien, et voilà les 4 fonctions pour calculer les distances, une si le deux points sont en cartesien, une si les deux sont en polaire, une si le premier est polaire le deuxième cartesien, une si le premier est cartésien et le deuxieme polaire… ». Là gros boulot, non seulement tu te tapes tous les décalages d’index et la variable supplémentaire pour le type de coordonnées du point, mais en plus pour ton calcul de « distance_a_tester » tu dois désormais faire un if avec cas, chacun avec une condition double, pour appeler la bonne fonction (parce que tes collègues sont des branleurs, ils t’ont fourni 4 fonctions au lieu d’une seule qui s’adapte en fonction du type de coordonnées de chaque point).
Puis finalement, quand tu as fini, on te dit qu’en plus on ajoute à chaque point une couleur (codée sur un entier) et un identifiant numérique. Tu n’en as strictement rien à foutre, ces éléments ne servent pas à un seul moment dans le traitement dont tu es responsable. Mais tu vas quand même devoir en tenir compte, puisqu’en entrée tu auras désormais 6 entiers pour chaque point et en sortie 12.
Maintenant, avec l’approche objet. Tes collègues sont responsables de la définition des objets de type Point, objets qui portent une méthode distance_vers() prenant un autre objet de type point en paramètre, et d’un objet CouplePoints qui contient deux points A et B.
D’abord, ton code de base devient tout de suite beaucoup plus simple, tu ne te soucies plus du tout de la façon dont est défini un point, tu n’as plus de calculs d’index, tu manipules beaucoup moins de variables :
calc_point_le_plus_proche(Point[] points):
__nb_points = taille(points)
__resultat = CouplePoints[nb_points]
__pour i de 0 a nb_points - 1:
____point = points[i]
____resultat[i] = CouplePoints(point, null)
____distance_min = -1
____pour j de 0 a nb_points - 1 et j != i
______point_a_tester = points[j]
______distance_a_tester = calc_distance(point, point_a_tester)
______si distance_min == -1 ou distance_min < distance_a_tester:
________resultat[i].B = point_a_tester
________distance_min = distance_a_tester
__retourne resultat
Mais en plus maintenant, quand tes collègues modifient la définition de Point, ce n’est plus ton problème, ton code ne bouge plus d’un poil. Parce que ton code n’a aucune dépendance sur la logique interne de l’objet Point. Ils peuvent introduire des systèmes de coordonnées différents, ils peuvent ajouter autant d’attributs qu’ils veulent sur les points. Ça ne changera rien à ton code. Ils peuvent même modifier le type de retour de la fonction distance, par exemple pour renvoyer un objet de type Distance qui combine une valeur et une unité, et mixer des points avec des distances en miles et d’autres avec des kilomètres, ça n’affectera toujours pas ton code (tant que sur leur type distance ils implémentent correctement l’opérateur < pour donner le bon résultat quelque soit l’unité).
Résultat, le code est :
- plus lisible => code plus concis, plus de calculs d’index, moins de variables,
- plus facile à tester => pour les mêmes raisons,
- plus facile à maintenir => il n’y a que si on change la définition de ta fonction qu’elle doit être modifiée, tout autre changement de définition dans l’application n’affecte pas ta fonction,
- plus facile à réutiliser => ta fonction n’étant pas dépendante de la définition du point, elle peut être réutilisée pour tout type d’objet ayant une fonction distance()
Et le corolaire de tout ça, c’est aussi que le code sera plus fiable. Car un code plus simple, plus facile à tester et à maintenir, c’est un code qui a moins de risque de contenir des bugs et d’en introduire de nouveaux lors des évolutions.