Je lisais cette page , sur le moment où les getters / setters sont justifiés, et l'OP a donné l'exemple de code suivant:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
La réponse acceptée indique:
Soit dit en passant, dans votre exemple, je donnerais à la classe
Fridge
les méthodesputCheese()
ettakeCheese()
, au lieu deget_cheese()
etset_cheese()
. Ensuite, vous auriez toujours l'encapsulation.
Comment l'encapsulation est-elle préservée en la renommant de get / set en putCheese()
/ takeCheese()
Vous obtenez évidemment / définissant une valeur, alors pourquoi ne pas simplement la laisser comme get / set?
Dans la même réponse, il indique également:
Avoir des getters et des setters ne rompt pas en soi l'encapsulation. Ce qui rompt l'encapsulation, c'est l'ajout automatique d'un getter et d'un setter pour chaque membre de données (chaque champ, en java java), sans y penser.
Dans ce cas, nous n'avons qu'une seule variable, cheese
et vous voudrez peut-être prendre et retourner le fromage au réfrigérateur, donc une paire get / set dans ce cas est justifiée.
la source
putCheese
ajouterait du fromage au réfrigérateur ettakeCheese
l'enlèverait - ce sont des abstractions orientées domaine (de niveau supérieur), plutôt que des getters et setters de champ d'objet (qui sont des abstractions de programmation informatique (de bas niveau)).Réponses:
Je pense que tu ne comprends pas. Cela ne veut pas dire que vous devez renommer le setter et le getter, mais avoir des méthodes qui ajoutent et retirent des éléments du réfrigérateur. c'est à dire
Maintenant, la variable privée est encapsulée. Je ne peux pas simplement le régler sur tout ce que je veux, je peux seulement ajouter et retirer des tranches de fromage du réfrigérateur en utilisant les méthodes, qui à leur tour garantissent que les règles de logique commerciale du fromage que je veux sont appliquées.
la source
setCheese()
avoir la même logique dans le setter. Pour moi, de toute façon, vous essayez de cacher le fait que vous utilisez un setter en renommant la méthode, mais votre getter / setting évidemment quelque chose.AddCheese(Integer.MAX_VALUE)
devrait échouer, mais ne le fera pas.Les getters et setters rompent l'encapsulation à chaque fois , par définition. On pourrait dire que parfois nous devons le faire. Avec cela à l'écart, voici mes réponses:
La différence réside dans la sémantique, c'est-à-dire la signification de ce que vous écrivez. L'encapsulation ne consiste pas seulement à protéger, mais à cacher l'état interne. L'état interne ne doit même pas être connu à l'extérieur, mais il est prévu que l'objet propose des méthodes pertinentes pour l'entreprise (parfois appelées "comportement") pour manipuler / utiliser cet état.
Donc
get
, ceset
sont des termes techniques qui semblent n'avoir rien à voir avec le domaine "réfrigérateur", alorsput
que celatake
pourrait avoir du sens.Toutefois , si
put
outake
faire réel sens dépend toujours des exigences et ne peut être jugé objectivement. Voir le point suivant:Cela ne peut être objectivement déterminé sans plus de contexte. Votre exemple contient une
go_shopping()
méthode ailleurs. Si c'est à cela qu'ilFridge
sert, alors il n'a pas besoinget
ouset
, ce dont il a besoinFridge.go_shopping()
. De cette façon, vous avez une méthode dérivée des exigences, toutes les "données" dont il a besoin sont locales et vous avez un comportement réel au lieu d'une structure de données à peine voilée.N'oubliez pas que vous ne construisez pas un générique réutilisable
Fridge
. Vous construisez unFridge
pour vos besoins uniquement. Tout effort dépensé pour en faire plus que ce qu'il doit être est en fait un gaspillage.la source
Getters and setters break encapsulation every single time
- C'est un peu trop formulé à mon goût. Les méthodes (y compris les getters et setters) ont le même objectif que les portes lors d'un concert: elles permettent une entrée et une sortie ordonnées du lieu.public int getFoo()
il est presque impossible, en pratique, de passer à un autre type.Presque tout cela montre une incompréhension fondamentale de l'encapsulation et de la manière dont elle s'applique.
La réponse initiale selon laquelle vous rompiez l'encapsulation est tout simplement fausse. Votre application peut avoir besoin de simplement définir la valeur du fromage dans le réfrigérateur au lieu d'augmenter / diminuer ou d'ajouter / supprimer. De plus, ce n'est pas de la sémantique, peu importe comment vous l'appelez, si vous avez besoin d'accéder et / ou de modifier des attributs, vous ne rompez pas l'encapsulation en les fournissant. Enfin, l'encapsulation ne consiste pas vraiment à "cacher", il s'agit de contrôler l'accès à l'état et aux valeurs qui ne devraient pas avoir besoin d'être publiques ou manipulées en dehors de la classe, tout en l'accordant à ceux qui le devraient et en effectuant la tâche mise à disposition en interne.
Un getter ou un setter ne rompt pas l'encapsulation lorsqu'il existe un besoin légitime d'obtenir ou de définir une valeur. C'est pourquoi les méthodes peuvent être rendues publiques.
L'encapsulation consiste à conserver les données et les méthodes qui modifient ces données directement ensemble dans un seul endroit logique, la classe.
Dans ce cas particulier, il est clairement nécessaire de modifier la valeur du fromage dans l'application. Quelle que soit la façon dont cela est fait, via get / set ou add / remove, tant que les méthodes sont encapsulées dans la classe, vous suivez le style orienté objet.
Pour plus de précision, je vais donner un exemple de la façon dont l'encapsulation est rompue en fournissant un accès indépendamment du nom de la méthode ou de l'exécution logique.
Supposons que votre réfrigérateur ait une "durée de vie", juste un certain nombre de tiques avant que le réfrigérateur ne soit plus opérationnel (pour des raisons d'argument, le réfrigérateur ne peut pas être réparé). Logiquement, il est impossible qu'un utilisateur (ou le reste de votre application) puisse modifier cette valeur. Cela devrait être privé. Il ne serait visible qu'à travers, par exemple, un attribut public différent appelé "isWorking". À l'expiration de la durée de vie, le réfrigérateur fonctionne en interne et fonctionne à faux.
L'exécution du décompte à vie et son actionnement de l'interrupteur isWorking sont toutes internes au réfrigérateur, rien à l'extérieur ne devrait / ne devrait pouvoir effectuer le processus. isWorking ne doit être visible que par conséquent, un getter ne rompt pas l'encapsulation. Cependant, l'ajout d'accesseurs pour des éléments du processus de durée de vie briserait votre encapsulation.
Comme la plupart des choses, la définition de l'encapsulation n'est pas littérale, elle est relative. Devriez-vous voir X en dehors de la classe? Devriez-vous être en mesure de changer Y? Est-ce que tout ce qui s'applique à votre objet ici dans cette classe ou la fonctionnalité est-elle répartie sur plusieurs classes?
la source
Il ne s'agit pas seulement de renommer une méthode. Les deux méthodes fonctionnent différemment.
(Imaginez ceci dans votre esprit)
get_cheese et set_cheese expose le fromage. putCheese () et takeCheese () gardent le fromage caché et prennent soin de le gérer et donnent à l'utilisateur un moyen de le gérer. L'observateur ne voit pas le fromage, il ne voit que deux méthodes pour le manipuler.
la source