Disons que j'ai une classe simple qui stocke les amis d'un utilisateur dans une ArrayList de chaînes, avec un getter pour accéder à cette ArrayList:
public class User
{
private ArrayList<String> mFriends;
// ...other code like constructors and setters...
public ArrayList<String> getFriends()
{
return mFriends;
}
}
Puisque Java et de nombreux autres langages le sont (de manière équivalente) pass-by-reference, cela ne permet pas à l'appelant de getFriends () d'accéder directement à mon ArrayList de chaînes c'est-à-dire qu'ils pourraient le modifier sans même appeler mon setter?
Je sens cela rompt énormément le concept d'encapsulation. Existe-t-il une solution de contournement normale pour cela, en plus de créer dynamiquement une nouvelle ArrayList avec les mêmes valeurs et de renvoyer cela, ou est-ce que je ne comprends pas quelque chose?
Edit: Je comprends que Java n'est pas vraiment pass-by-reference mais passe plutôt une copie de l'adresse de l'objet d'origine, mais cela a le même effet que le passage par référence lors de l'exposition d'objets à ceux qui sont en dehors de votre classe
3 Réponses :
Si vous vous inquiétez de l'encapsulation, vous pouvez renvoyer une copie de votre liste, par exemple
public ArrayList<String> getFriends() {
return new ArrayList<>(mFriends);
}
Au fait, Java n'est pas vraiment pass-by-reference mais plutôt pass-by-value .
Oui désolé, j'ai édité mon passé concernant le commentaire de passage par référence. Cependant, je ne peux pas croire que créer une nouvelle copie à chaque fois serait performant, comme je l'ai spécifiquement dit dans mes commentaires "en plus de créer dynamiquement un nouveau ArrayList"
@GaryAllen C'est comme ça. Et les performances devraient être le cadet de vos soucis dans ce cas.
.clone () ); new ArrayList <> (yourObjectHere) ); Merci, le commentaire Reference Escape était principalement ce que je recherchais. Cette vidéo m'aide aussi beaucoup. Appréciez-le. (vidéo: youtube.com/watch?v=nW48K2a6t7k )
Vous avez raison pour les objets mutables . Vous pouvez envelopper le champ avec Collections.unmodifiableList et autres. Ce que l'on voit aussi, c'est que les collections (mutables) n'ont tout simplement pas de getters, mais addFriend , getFriend (index) et autres.
En fait, les getters (et en particulier les setters) ne sont plus un modèle très estimé.
Le préfixe du membre "m" est à mon avis mieux adapté aux autres langues.
Malgré le fait que votre réponse indique le comportement correct, je pense que c'est un peu trompeur en termes de sémantique de ce que la question pose. C'est le problème de l'échappement des références.
@GiorgiTsiklauri En effet, j'ai même voté pour votre réponse. Le problème avec la POO est que son concept de base (historique) est celui d'un état interne. Pouvez-vous atteindre via des méthodes d'accès un objet mutable, alors cela devrait être un comportement prévu . J'ai principalement répondu, car laisser les getters renvoyer une copie me paraissait une technique plutôt faible.
Ce contre quoi vous vous protégez ici, c'est le code extérieur qui modifie à quel
ArrayListmFriendsfait référence. Mais comme vous l'avez noté, il est toujours possible pour du code extérieur de modifier le contenu de cette liste. Si vous voulez vous protéger contre cela, vous pouvez peut-être utiliserCollections.unmodifiableList, ou renvoyer une copie.Oui, c'est exactement ce que je veux dire. Comment cela fonctionnerait-il en ce qui concerne le renvoi d'objets Java "standard" non intégrés? Dois-je simplement faire confiance à l'utilisateur pour qu'il ne modifie pas son contenu sans utiliser mon setter, par exemple?
S'il est important qu'ils ne modifient pas le contenu, vous devriez probablement leur empêcher de le faire. Si vous mettez quelque chose à la disposition des utilisateurs, il y a un risque assez élevé que quelqu'un l'utilise indépendamment de ce que vous recommandez.
La reponse courte est oui'. Mais vous avez la responsabilité en tant que concepteur de ne pas exposer l'implémentation interne de votre classe au monde extérieur. Rendre
mFriendsprivé puis fournir une méthode getter n'est pas différent de le rendre public. Considérez plutôtreturn Collections.unmodifiableList (mFriends).Vous savez peut-être que des articles comme Pourquoi les méthodes getter et setter sont mauvaises circulent depuis des décennies.