IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

getter, setter et références sur objets


Sujet :

Langage Java

  1. #21
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Citation Envoyé par rtg57 Voir le message
    L'origine de cette question vient du fait que j'ai tendance à utiliser une variable ou un objet, plusieurs fois dans une même méthode. Je m'explique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void maMethode()
    {
      Date maDate;
    /.../
      maDate = maClasse.getDateNaissance(); // Le fameux getter
    /.../
      maDate = uneReponseDeFonction();
    }
    Ici :
    • tu déclares une variable maDate de type Date
    • puis tu fais pointer cette variable vers l'objet renvoyé par maClasse.getDateNaissance()
    • puis tu fais pointer cette variable vers l'objet renvoyé par uneReponseDeFonction(), en "jetant" l'ancienne référence, qui n'est aucunement modifiée par cette action !


    Il y pourrait y avoir problème si tu effectuais les actions suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void maMethode()
    {
      Date maDate;
    /.../
      maDate = maClasse.getDateNaissance(); // Le fameux getter
    /.../
      maDate.setDate(0); // appel d'une méthode qui modifie effectivement l'état interne de l'objet (on pourraitt appeler toString sans problème)
      letsChangeThisDate(maDate); // appel d'une fonction qui agit potentiellement sur les objets passés en paramètres
    }

  2. #22
    Membre éclairé Avatar de Heimdal
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    549
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 549
    Points : 718
    Points
    718
    Par défaut
    Il y pourrait y avoir problème si tu effectuais les actions suivantes:
    Pas seulement. Dés lors qu'il y a un getter public sur une Date qui est utilisé par différents points de programme, il y a problème potentiel... Exemple en étant simple utilisateur maladroit de la classe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public final class MonObjet {
     
    	private static final Date ZERO = getZero();
     
    	private final Date birthday;
     
    	private MonObjet(Date birthday) {
    		this.birthday = birthday;
    	}
     
    	public static MonObjet newInstance(Date birthday) {
    		return new MonObjet(birthday);
    	}
     
    	public Date getBirthday() {
    		return birthday;
    	}
     
    	public boolean bornBeforeJC() {
    		return ZERO.after(birthday);
    	}
     
    	private static Date getZero() {
    		Calendar cal = Calendar.getInstance();
    		cal.clear();
    		cal.set(0, 0, 1);
    		return cal.getTime();
    	}
    }
    Et en l'utilisant maladroitement à l'extérieur, je peux entrainer un fonctionnement non désiré:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static void main(String[] args) {
    		MonObjet monObjet = MonObjet.newInstance(new Date());
    		System.out.println("Born before JC?"+monObjet.bornBeforeJC());
    		monObjet.getBirthday().setTime(Long.MIN_VALUE);
    		System.out.println("Born before JC?"+monObjet.bornBeforeJC());
    	}
    Ça me retourne:
    Born before JC?false
    Born before JC?true
    Donc dans le cas d'un objet mal fichu comme Date et s'il n'est pas prévu que ta date soit modifiée de l'extérieur, il n' y a que la copie défensive ou la restriction de portée...
    As-tu réellement besoin d'exposer ta Date (ou plus généralement ton objet) de manière publique?

  3. #23
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut
    Bonjour,

    oui j'expose l'objet Date dans la mesure où j'ai une classe qui stocke les données d'individus, dont la date de naissance, et qui doit pourvoir la fournir à d'autres classe de traitement.

    Je veux passer par des getter / setter pour maitriser les données stockées, mais je m'aperçois que le getter retourne la référence de l'objet.
    Cet objet private dans la classe des données est exposé publiquement à toute classe demandant la valeur de celui-ci à travers le getter.
    Dans ce cas précis, je contourne un peu le problème en retournant la valeur sous format long:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return dateNaissance.getTime();
    . Ceci étant un type primitif, je suis donc assuré que c'est une copie qui est renvoyé.

    Dans le cas de String comme pour le patronyme des individus, je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return new String ( patronymeIndividu );
    . Dans ce cas, je pense que cette précaution est inutile puisque l'on m'a indiqué dans cette discussion que le type String retourne toujours une autre instance de l'objet, et pas l'objet lui-même.

    Je constate en tout cas que je dois être très prudent lorsque je récupère une donnée à travers un getter, car finalement, elle n'est pas si protégée que cela.

    Merci & @ bientôt...
    @ bientôt...

    Salut & @+ sur 3W!

  4. #24
    Membre éclairé Avatar de Heimdal
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    549
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 549
    Points : 718
    Points
    718
    Par défaut
    Oui pour ta String c'est inutile...
    Après c'est sans doute une question de gout mais je préfère renvoyer une Date à sa version long, quitte à perdre du temps en en renvoyant une copie.

  5. #25
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par rtg57 Voir le message
    Dans le cas de String comme pour le patronyme des individus, je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return new String ( patronymeIndividu );
    . Dans ce cas, je pense que cette précaution est inutile puisque l'on m'a indiqué dans cette discussion que le type String retourne toujours une autre instance de l'objet, et pas l'objet lui-même.
    Non : c'est inutile car String est un type immuable, qui ne peut donc pas être modifié.

    Il n'y a donc pas à le protéger. On peut le partager sans problème...

    a++

  6. #26
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Citation Envoyé par Heimdal Voir le message
    Pas seulement.
    L'exemple que tu donnes (monObjet.getBirthday().setTime(Long.MIN_VALUE);) est justement un de ceux que j'ai donné


    Dans cette discussion, tout le monde est d'accord pour dire que, lorsqu'une classe A renvoie directement un de ses objets internes (non immutable), il y a un risque pour que le code appelant modifie cet objet, ce qui peut avoir des effets non désirés sur la classe A.
    Après, les positions varient entre "il faut coder son API en mode défensif pour empêcher les utilisateurs de faire n'importe quoi" et "si l'utilisateur fait n'importe quoi c'est son problème"...

    Cependant, dans le dernier post de rtg57, c'est un autre problème qui est évoqué : visiblement, rtg57 a l'habitude d'utiliser une même variable pour y stocker successivement des objets différents.
    J'imagine qu'il tient ça de ses réflexes C/C++, où l'on essaie au maximum de mutualiser les espaces mémoire utilisés... Personnellement, je préfère définir une variable différente pour chaque "donnée" représentée, avec un nom parlant et un scope le plus réduit possible autour du moment où je l'utilise effectivement. Je trouve ça bien plus lisible qu'un code "à la C" avec des variables plus ou moins globales utilisées pour 12 rôles différents et réinitialisées dans 36 boucles et fonctions[*].
    En tous cas, même si cette façon de réutiliser les variables n'a pas vraiment lieu d'être en Java, il est certain que l'affectation d'un nouvel objet à une variable ne modifie aucunement l'objet vers lequel pointait précédemment cette variable.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    Date maDate = new Date();
    // je crée un nouvel objet 1 avec un nouvel espace mémoire et je fais pointer maDate vers cet objet
     
    maDate = new Date();
    // je crée un nouvel objet 2 avec un nouvel espace mémoire et je fais pointer maDate vers cet objet
    // la référence à l'objet 1 est perdue, l'espace mémoire 1 sera récupéré plus tard par le garbage collector
     
    maDate = trucmuche.getDate();
    // je fais pointer maDate vers trucmuche.date
    // la référence à l'objet 2 est perdue, l'espace mémoire 2 sera récupéré plus tard par le garbage collector
     
    maDate = new Date();
    // je crée un nouvel objet 3 avec un nouvel espace mémoire et je fais pointer maDate vers cet objet
    // la référence à trucmuche.date existe encore dans trucmuche mais elle n'a plus aucun rapport avec la variable maDate


    [*] Déjà vu. Déjà refactorisé. Après que je lui ai soumis ma refactorisation, le programmeur à l'origine du code initial m'a alors dit quelque chose dans le style "ouaaaah, c'est plus simple, c'est plus clair, et puis j'en apprends des choses, je ne connaissais pas l'héritage c'est génial ce truc". Ce programmeur codant en Java sans même connaître la notion d'héritage était probablement plus à blâmer que le "style de programmation à la C".

  7. #27
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Citation Envoyé par rtg57 Voir le message
    oui j'expose l'objet Date dans la mesure où j'ai une classe qui stocke les données d'individus, dont la date de naissance, et qui doit pourvoir la fournir à d'autres classe de traitement.
    Si tu veux exposer une propriété de ton objet sans donner la possibilité de modifier sa valeur (read-only), il faut soit renvoyer un type primitif ou un type immutable (qui par nature ne peuvent pas être modifiés), soit renvoyer une copie plus ou moins profonde de la propriété (la copie sera éventuellement modifiée mais cela n'affectera pas ton objet).
    Si tu veux laisser la responsabilité au code appelant de modifier ou non ta propriété, tu peux renvoyer directement l'objet en question.
    Si tu veux permettre au code appelant de modifier la propriété, mais pas n'importe comment, il faut encapsuler les méthodes permettant de modifier la propriété dans des méthodes ne présentant à l'extérieur que le type d'action que tu veux permettre.


    Exemple à la con : un compteur qui utilise un entier "mutable".
    Méthode 1 : je laisse le code appelant faire ce qu'il veut via un getter et un setter, il est alors de sa responsabilité de ne pas faire n'importe quoi avec mon compteur, comme par exemple y mettre un nombre négatif, ou ajouter 2 d'un coup, ou modifier "par erreur" le WrappedInteger renvoyé par le getter...
    Méthode 2 : j'estime que le fonctionnement de mon compteur doit être bridé, je m'arrange donc pour renvoyer une copie de mon WrappedInteger via le getter, et j'encapsule les méthodes permettant de modifier sa valeur plutôt que de présenter directement un setter.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    class WrappedInteger {
    	private int value;
    	public WrappedInteger(int value) { this.value = value; }
    	public int getValue() { return this.value; }
    	public void setValue(int value) { this.value = value; }
    	public WrappedInteger clone() { return new WrappedInteger(this.value); }
    }
     
    class Compteur1
    {
       private WrappedInteger value;
       public Compteur1() { value = new WrappedInteger(0); }
       public WrappedInteger getValue() { return value; }
       public void setValue(WrappedInteger val) { value = val; }
    }
     
    class Compteur2
    {
       private WrappedInteger value;
       public Compteur2() { value = new WrappedInteger(0); }
       public WrappedInteger getValue() { return value.clone(); }
       public void reset() { value.setValue(0); }
       public void increment() { value.setValue(value.getValue()+1); }
    }

  8. #28
    Membre expérimenté Avatar de rtg57
    Homme Profil pro
    Autodidacte
    Inscrit en
    Mars 2006
    Messages
    1 340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Autodidacte
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 340
    Points : 1 576
    Points
    1 576
    Par défaut
    Merci à tous pour ces explications détaillées,

    je vais m'mprimer cette discussion et méditer dessus

    @ bientôt...
    @ bientôt...

    Salut & @+ sur 3W!

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 0
    Dernier message: 25/02/2014, 16h01
  2. [POO] Perte de la référence sur mon objet (this) lors d'un évènement
    Par muad'dib dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 20/12/2008, 12h59
  3. référence sur la méthode d'un objet
    Par kirbby dans le forum Langage
    Réponses: 2
    Dernier message: 25/04/2008, 11h17
  4. Réponses: 2
    Dernier message: 13/12/2006, 13h39
  5. [VB6] faire référence à un objet situé sur un autre form
    Par coyott dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 15/05/2006, 15h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo