Modifications du design de la classe de base après le déploiement
Mise à jour : novembre 2007
Dans l'idéal, les hiérarchies de classe ne changent jamais après leur déploiement car des modifications minimes peuvent avoir des conséquences inattendues. En réalité, il n'est pas toujours possible d'éviter ces modifications : les exigences des produits peuvent varier et les spécifications de conception omettent parfois des éléments principaux. Une catégorie des problèmes liés à l'héritage est appelée problème de classe de base fragile.
Problème de classe de base fragile
Le principal inconvénient lié à l'utilisation des hiérarchies d'héritage est un problème connu sous le nom de classes de base fragiles. Les modifications apportées aux classes de base nécessitent souvent que la classe de base et que le code des classes dérivées soient modifiés, recompilés et redistribués. Ce problème est d'autant plus ardu lorsque plusieurs développeurs créent la classe de base et les classes dérivées, car chacune des parties peut refuser l'accès à son code source. Dans le pire scénario, un client peut utiliser par inadvertance la forme binaire compilée d'une classe de base mise à jour avec la version binaire d'origine incompatible des classes dérivées.
Les modifications de la classe de base pouvant endommager les classes dérivées sont notamment la substitution ou la modification des types de données des membres de la classe de base.
Limitation des problèmes de classe de base fragile
La meilleure solution pour éviter ce problème consiste à apporter des modifications uniquement dans les classes dérivées. Toutefois, cette solution n'est pas toujours possible car vous devez considérer chaque possibilité lors de la première version de la classe de base. Il n'est cependant pas toujours possible d'éviter des modifications imprévues de la classe de base, en dépit des efforts déployés.
Les classes MustInherit et les méthodes MustOverride permettent de réduire ce problème car les détails relatifs à l'implémentation sont déplacés vers les classes dérivées, et la nécessité de modifier la classe de base est réduite. Ce n'est toutefois pas toujours possible, même si vous disposez de la meilleure planification possible.
Les données membres masquées des classes dérivées sont également utiles, car ils réduisent les conflits de noms avec les membres de la classe de base.
Le moyen le plus sûr pour étendre les fonctionnalités d'une classe de base est de lui ajouter de nouveaux membres. La seule façon pour que de nouveaux membres interrompent une classe de base est lorsque la classe dérivée utilise le mot clé Overloads pour hériter de méthodes de la classe de base et introduire de nouvelles méthodes portant le même nom. Il est possible d'éviter ce problème en spécifiant explicitement dans la classe dérivée les méthodes de la classe de base qui doivent être héritées de la base, en redéfinissant ces méthodes et en les déléguant à celles-ci.
Toutes les classes de base sont fragiles à un certain point. Dans l'analyse finale, le problème de la classe de base fragile ne peut pas être évité ; vous pouvez toutefois le minimiser par une conception minutieuse des hiérarchies de classe pour réduire la nécessité de modifier la classe de base et par un test poussé permettant de déterminer le moment où ces modifications ne peuvent pas être évitées.