Je suis en train de lire le code complet où McConnell encourage fortement à faire de toutes les variables privées. Coïncidentalement, je viens de travailler sur un projet où je devais changer une variable privée. P>
La classe avait une variable privée (une chaîne code> code>) indiquant où charger une image à utiliser dans le système chrome. Je devais changer cette image, je ne connais pas d'autres langues, mais aussi loin que je connais dans Flex / Air, il n'ya aucun moyen de remplacer une variable privée. P>
Si cela avait été déclaré protégé, j'aurais pu simplement étendre la classe et remplacer cette variable. Mais puisque c'était privé, je devais copier tout le code de la classe et créer une classe de duplication avec la seule différence étant cette chaîne. P>
Je pense que l'argument est d'utiliser privé car il fabrique un couplage plus souple entre super et sous-classes, mais j'ai dû violer complètement le sécher pour pouvoir obtenir un changement de chaîne simple, ce qui me semble plus pire. P>
Cela me fait penser que protégé est meilleur que privé. Cependant, je veux faire des choses les bonnes pratiques. Donc, si privé est meilleur, je veux comprendre pourquoi. P>
Si le consensus général est que privé est préférable, quelqu'un peut-il expliquer pourquoi? P>
10 Réponses :
Faire des variables En général, je dirais utiliser le type d'accès qui masque la variable de classes et / ou de paquets extérieurs. P> privé code> pour quand vous savez que la classe particulière définie sera la seule à utiliser ces variables. Toutefois, si vous souhaitez étendre une classe, vous devez utiliser protégé code>. Privé est vraiment pour que vous n'utilisiez pas de variables globalement (vous utilisez donc des getters et des setters dans des classes) qui permet de relâcher les couples. Protégé est parfaitement acceptable lors de l'extension d'une classe. P>
Dans ce cas, l'emplacement de cette image était une caractéristique privée spécifique à la mise en œuvre de la classe de base. Vos nouvelles exigences signifiaient que cela devait pouvoir varier d'une classe dérivée à une autre.
Vous devez garder le champ membre privé, mais définissez une propriété virtuelle protégée pour l'exposer aux classes dérivées: P>
private const string _myImagePath = @"C:\other.bmp";
protected override string ImagePath {
get {return _myImagePath;}
}
Yup, exactement. Ne touchez pas la variable parent, remplacez la getter à la place. Beaucoup plus encapsulé et moins sujet aux erreurs.
Tout ce qui fait partie de la mise en œuvre de la classe doit être privé, ce qui vous fait avoir la liberté de le changer si le besoin se pose. P>
Dans l'exemple que vous avez mentionné, l'interface de la classe n'était peut-être pas complètement définie car vous devez modifier une propriété privée de la classe. Si vous avez le contrôle du code, vous pouvez créer la propriété protégée ou ajouter des fonctions pour obtenir et définir la valeur. P>
"Meilleure pratique" est lui-même un terme subjectif, alors qu'il existe de nombreuses conventions qui servent à améliorer son code, la valeur de chacun doit être contrastée avec les exigences du problème que vous essayez de résoudre. P>
La déclaration de cette variable en tant que privé doit être considérée comme une expression des intentions de développement pour la variable (c'est-à-dire une utilisation interne), ce qui signifie que vous devez constante trouver un autre point d'extensibilité ou duplicate. P>
Dans une perspective de conception de l'API, il convient d'utiliser des détails de mise en œuvre privés pour isoler les appelants et protégé pour exposer des éléments à des héritiers p>
S'il avait été déclaré protégé, je aurait pu simplement étendre la classe, et remplacé cette variable. Mais Depuis qu'il était privé, je devais copier tout le code de la classe et créer une classe de duplication avec le seul différence étant cette chaîne. p> blockQuote>
Et s'il y avait eu un setter pour l'emplacement de l'image, vous n'avez pas besoin d'une sous-classe (ou d'une nouvelle classe) du tout. p>
Et si au lieu de vouloir changer l'image, vous auriez voulu un autre changement mineur, puis peut-être faire une autre API protégée / virtuelle peut avoir aidé. Ou peut-être pas. Mon seul point est qu'il est difficile de regarder une fois d'exemple nébuleux comme celui-ci et de dériver la sagesse générale de celle-ci. P>
Il y a un compromis entre la quantité de flexibilité qu'une classe vous donne en termes de comportement et de son extensibilité, ainsi que de la quantité d'efforts nécessaire pour concevoir et tester la classe (et les interactions supplémentaires entre la compréhension, bien documentées, etc. la classe est). Ces compromis de conception ne peuvent pas être évalués dans un vide, mais ils doivent être évalués dans leur contexte. Quelle est la probabilité que les différentes fonctionnalités / comportements / extensions / changements d'une classe pourraient em> éventuellement prendre en charge effectivement em> vont être? La classe bien conçue est celle qui présente des extensions pour les scénarios communs nécessaires et qu'il manque des extensions et des API inutiles. (Et pour les extensions qui y sont, il existe un choix entre des "constôtres" simples et une extensibilité variée / virtuelle / sous-classement plus complexe ... Ce dernier n'est pas un compromis à opter à la légère.) P>
Je ne sais pas que cela répond bien à votre question spécifique bien (ou du tout), mais la façon dont j'ai lu votre question, cela m'a fait avoir envie de dire que "c'est mieux pour les classes d'être des couteaux suisses-armée Parce que l'extensibilité / la personnalisabilité est bonne »et je voulais appeler que ces« bonnes »choses viennent avec des compromis. En outre, votre question semblait impliquer que cette situation portait sur le «privé» par rapport à «protégé» et «protégé» », alors que je pense qu'une simple« méthode de setter »serait un changement d'API suffisant. P>
Private est, IMO, toujours préférable au début, puis rendez-vous public / protégé à mesure que le besoin survient. Il est beaucoup plus facile de créer une nouvelle méthode que de tenter de supprimer la fonctionnalité que quelqu'un dépend de. P>
Dans ce cas, je penserais que la meilleure approche aurait toujours été d'avoir simplement inclus un setter. Y a-t-il eu une autre fonctionnalité que votre sous-classe a dû fournir ou pourriez-vous simplement créer une nouvelle instance, définir le chemin et être fait avec elle? P>
Faites-le privé jusqu'à ce qu'il soit protégé. Ceci est un problème d'abstraction avec des langues telles que C #, C ++ et Java où sont protégés / privés sont liés à la mise en œuvre. Les membres privés peuvent être automatiquement inlinés automatiquement alors que protégé ne le peuvent pas. Ceci est similaire au problème d'abstraction en C # et en C ++ avec monomorphisme et polymorphisme nécessitant le mot-clé virtuel. P>
Cela fait essentiellement un problème de classe de base fragile. Définir tout comme protégé / virtuel est le plus sûr en termes de réutilisation mais empêche les optimisations. Définir tout comme privé / non virtuel est le plus efficace. P>
Dans une langue comme Eiffel, le compilateur détecte automatiquement si des fonctions peuvent être inlinées et détecter automatiquement si une fonctionnalité est polymorphe ou monomorphe. http://dev.eiffel.com p>
Quand j'ai commencé à commencer à OO, je faisais tout ce que Alors que j'ai eu plus d'expérience, deux choses sont arrivées: p>
Maintenant mon approche est la suivante: faites-le Un bon public code> ou protégé code>, figurer: "Pourquoi devrais-je limiter ce que les autres personnes voulaient faire avec mon code ? " p>
privé code> jusqu'à ce que vous ayez besoin de le faire public code> (ou protégé code>) - et même alors, pense difficile de savoir si c'est vraiment la bonne solution. P>
Protectey code> est un point d'extensibilité em> intentionnel em>, placez-y par le concepteur. J'ai constaté que la conception d'une extensibilité est en fait une sorte de dur, et vous devez faire em>. Si vous laissez simplement l'ouvrir et l'espoir, vous demandez des cauchemars de maintenance sur la route. < / p>
Je suis peut-être le seul ici qui est d'accord avec ce que je pense que l'auteur implique. L'idée d'avoir à ouvrir une superclasse pour apporter des modifications à un accesseur peut ne pas être simple et peut toujours être une option. La méthode privée jusqu'à ce que la méthode protégée contre l'être protégée est ridicule et signifie finalement que vous n'avez pas vraiment de raison d'utiliser privé en premier lieu. p>
La vraie raison que vous voudriez garder un membre privé est de sorte qu'une instance d'une sous-classe ne puisse pas avoir d'accès inattendu aux membres d'une instance d'une superclasse qui devrait rester verrouillée. L'effet secondaire malheureux est le manque d'extensibilité. La solution top-vote de John Sanders est probablement la meilleure pratique car elle traite de ce problème. p>
Cependant, j'ai réussi à coder des milliers de classes avec une utilisation fréquente de variables protégées (et presque non privées) et n'a jamais eu rien d'appelerais un problème avec une utilisation inattendue. Il semble que la même chose puisse être accomplie en choisissant simplement de ne pas coder de manière à ne pas jouer avec d'autres classes valeurs protégées. P>
Donc en conclusion, je dis: p>
Les membres protégés font partie de l'API, car des classes dérivées dans d'autres packages (c'est-à-dire des colis en dehors de la volonté de votre organisation) peuvent les voir. En tant que tels, ils représentent un engagement. Les conseils pour préférer des montants privés à des conseils pour éviter de faire des engagements inutiles. Vous pouvez toujours faire un membre moins visible plus visible, mais vous ne pouvez pas toujours faire l'inverse. P>