Devriez-vous utiliser des variables membres protégées? Quels sont les avantages et quels problèmes cela peut-il causer?
Devriez-vous utiliser des variables membres protégées? Quels sont les avantages et quels problèmes cela peut-il causer?
Réponses:
Devriez-vous utiliser des variables membres protégées?
Cela dépend de la difficulté avec laquelle vous vous cachez.
Si un développeur arrive et sous-classe votre classe, il risque de le gâcher parce qu'il ne le comprend pas complètement. Avec les membres privés, autres que l'interface publique, ils ne peuvent pas voir les détails spécifiques de l'implémentation de la façon dont les choses sont faites, ce qui vous donne la flexibilité de le changer plus tard.
Le sentiment général de nos jours est qu'ils provoquent un couplage indu entre les classes dérivées et leurs bases.
Ils n'ont aucun avantage particulier par rapport aux méthodes / propriétés protégées (il était une fois, ils pouvaient avoir un léger avantage en termes de performances), et ils étaient également davantage utilisés à une époque où l'héritage très profond était à la mode, ce qui n'est pas le cas pour le moment.
no particular advantage over protected methods/properties
être no particular advantage over *private* methods/properties
?
super
construction pour appeler le constructeur parent; il s'occupera ensuite d'initialiser les variables d'état privées dans la classe parente.
Généralement, si quelque chose n'est pas délibérément conçu comme public, je le rends privé.
Si une situation survient où j'ai besoin d'accéder à cette variable ou méthode privée à partir d'une classe dérivée, je la change de privé en protégé.
Cela n'arrive presque jamais - je ne suis vraiment pas du tout fan de l'héritage, car ce n'est pas un moyen particulièrement efficace de modéliser la plupart des situations. En tout cas, continuez, pas de soucis.
Je dirais que c'est bien (et probablement la meilleure façon de procéder) pour la majorité des développeurs.
Le simple fait de la question est si un autre développeur arrive un an plus tard et décide qu'il a besoin d'accéder à votre variable de membre privé, il va simplement modifier le code, le changer en protégé et poursuivre ses activités.
Les seules vraies exceptions à cela sont si vous êtes dans le domaine de l'expédition de DLL binaires sous forme de boîte noire à des tiers. Il s'agit essentiellement de Microsoft, de ces fournisseurs de «Custom DataGrid Control» et peut-être de quelques autres grandes applications livrées avec des bibliothèques d'extensibilité. À moins que vous ne soyez dans cette catégorie, cela ne vaut pas la peine de consacrer du temps / des efforts à vous soucier de ce genre de choses.
Le problème clé pour moi est qu'une fois que vous faites une variable protégée, vous ne pouvez pas autoriser aucune méthode de votre classe à compter sur sa valeur dans une plage, car une sous-classe peut toujours la placer hors de plage.
Par exemple, si j'ai une classe qui définit la largeur et la hauteur d'un objet pouvant être rendu, et que je protège ces variables, je ne peux alors faire aucune hypothèse sur (par exemple) le rapport hauteur / largeur.
De manière critique, je ne peux jamais faire ces hypothèses à aucun moment à partir du moment où le code est publié en tant que bibliothèque, car même si je mets à jour mes setters pour maintenir le rapport hauteur / largeur, je n'ai aucune garantie que les variables sont définies via les setters ou accessibles via le getters dans le code existant.
Aucune sous-classe de ma classe ne peut non plus choisir de faire cette garantie, car elle ne peut pas non plus appliquer les valeurs des variables, même si c'est tout l'intérêt de sa sous-classe .
Par exemple:
En contraignant les variables à être privées, je peux alors appliquer le comportement que je souhaite via des setters ou des getters.
En général, je conserverais vos variables membres protégées dans les rares cas où vous avez un contrôle total sur le code qui les utilise également. Si vous créez une API publique, je dirais jamais. Ci-dessous, nous ferons référence à la variable membre comme une «propriété» de l'objet.
Voici ce que votre superclasse ne peut pas faire après avoir rendu une variable membre protégée plutôt que privée avec des accesseurs:
créer paresseusement une valeur à la volée lorsque la propriété est en cours de lecture. Si vous ajoutez une méthode getter protégée, vous pouvez créer paresseusement la valeur et la renvoyer.
savoir quand la propriété a été modifiée ou supprimée. Cela peut introduire des bogues lorsque la superclasse émet des hypothèses sur l'état de cette variable. Faire une méthode de définition protégée pour la variable conserve ce contrôle.
Définissez un point d'arrêt ou ajoutez une sortie de débogage lorsque la variable est lue ou écrite.
Renommez cette variable membre sans chercher dans tout le code qui pourrait l'utiliser.
En général, je pense que ce serait le cas rare où je recommanderais de créer une variable membre protégée. Vous feriez mieux de passer quelques minutes à exposer la propriété via des getters / setters que des heures plus tard pour rechercher un bogue dans un autre code qui a modifié la variable protégée. Non seulement cela, mais vous êtes assuré contre l'ajout de fonctionnalités futures (telles que le chargement paresseux) sans casser le code dépendant. Il est plus difficile de le faire plus tard que de le faire maintenant.
Au niveau de la conception, il peut être approprié d'utiliser une propriété protégée, mais pour l'implémentation, je ne vois aucun avantage à la mapper sur une variable membre protégée plutôt que sur des méthodes accesseur / mutateur.
Les variables membres protégées présentent des inconvénients importants car elles permettent au code client (la sous-classe) d'accéder à l'état interne de la classe de base. Cela empêche la classe de base de maintenir efficacement ses invariants.
Pour la même raison, les variables membres protégées rendent également l'écriture de code multithread sécurisé beaucoup plus difficile à moins d'être garantie constante ou confinée à un seul thread.
Les méthodes accesseur / mutateur offrent une stabilité d'API et une flexibilité de mise en œuvre considérablement plus élevées en maintenance.
De plus, si vous êtes un puriste OO, les objets collaborent / communiquent en envoyant des messages, pas en lisant / en définissant l'état.
En retour, ils offrent très peu d'avantages. Je ne les supprimerais pas nécessairement du code de quelqu'un d'autre, mais je ne les utilise pas moi-même.
La plupart du temps, il est dangereux d'utiliser protected car vous cassez quelque peu l'encapsulation de votre classe, qui pourrait bien être décomposée par une classe dérivée mal conçue.
Mais j'ai un bon exemple: disons que vous pouvez une sorte de conteneur générique. Il a une implémentation interne et des accesseurs internes. Mais vous devez offrir au moins 3 accès publics à ses données: map, hash_map, vector-like. Ensuite, vous avez quelque chose comme:
template <typename T, typename TContainer>
class Base
{
// etc.
protected
TContainer container ;
}
template <typename Key, typename T>
class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ }
template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }
template <typename T>
class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ }
J'ai utilisé ce genre de code il y a moins d'un mois (donc le code est de mémoire). Après réflexion, je pense que même si le conteneur Base générique devrait être une classe abstraite, même s'il peut très bien vivre, car utiliser directement Base serait tellement pénible qu'il devrait être interdit.
Résumé Ainsi, vous avez protégé les données utilisées par la classe dérivée. Néanmoins, nous devons tenir compte du fait que la classe Base doit être abstraite.
protected
n'est pas plus encapsulé que public
. Je suis prêt à avoir tort. Tout ce que vous avez à faire est d'écrire une classe avec un membre protégé et de m'interdire de le modifier. De toute évidence, la classe doit être non finale, car tout l'intérêt d'utiliser protected est l'héritage. Soit quelque chose est encapsulé, soit ce n'est pas le cas. Il n'y a pas d'état intermédiaire.
Bref oui.
Les variables membres protégées permettent d'accéder à la variable à partir de toutes les sous-classes ainsi que de toutes les classes du même package. Cela peut être très utile, en particulier pour les données en lecture seule. Cependant, je ne pense pas qu'ils soient jamais nécessaires, car toute utilisation d'une variable membre protégée peut être répliquée à l'aide d'une variable membre privé et de quelques getters et setters.
Pour plus d'informations sur les modificateurs d'accès .Net, cliquez ici
Il n'y a pas de réels avantages ou inconvénients aux variables membres protégées, c'est une question de ce dont vous avez besoin dans votre situation spécifique. En général, il est courant de déclarer les variables membres comme privées et de permettre l'accès extérieur via les propriétés. De plus, certains outils (par exemple certains mappeurs O / R) s'attendent à ce que les données d'objet soient représentées par des propriétés et ne reconnaissent pas les variables membres publiques ou protégées. Mais si vous savez que vous voulez que vos sous-classes (et UNIQUEMENT vos sous-classes) accèdent à une certaine variable, il n'y a aucune raison de ne pas la déclarer comme protégée.