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 :

Éclaircissement sur le référencement d'objet ?


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 93
    Par défaut Éclaircissement sur le référencement d'objet ?
    Bonjour à tous,

    J'essaie de développer une maquette d'application client / serveur avec ce que j'ai pu apprendre du java.

    Le principe est le suivant : une application cliente récupère une liste de données ("cache") envoyée par un serveur connecté à une base de données (en l'occurence MySQL). La liste est updatée en permanence (plusieurs aller-retours par action utilisateur), soit qu'elle reçoive de nouveaux objets, soit que les objets qu'elle contient sont mis à jour.

    Les objets subissent un traitement dès le serveur, et sont aussi traités et exploités dès leur arrivée au client pour être visuellement projetés et donner une sensation de fluidité. Pour ce faire, je veux éviter d'instancier de nouveaux objets à chaque modifications. Je conserve donc en mémoire du serveur les objets déjà envoyés au client pour les récupérer lors d'une sollicitation ultérieure, et lui renvoyer les mêmes.

    Je pensais m'en être sorti correctement, notamment en voulant profiter du fait que java fonctionne par référencement d'objet, et non par copie.

    Ainsi, l'objet o1 était envoyé au client pour alimenter un "objet client" de type O1(o1). Si le serveur modifiait o1, je pensais que le remplacement de l'ancien o1 par le nouvel o1 (o1.equals(o1) = true) dans le cache client suffisait à modifier dans le même temps le o1 référencé dans O1. Vous me suivez ?

    Or à ma grande surprise et à ma déception, ce n'est pas ce qui se passe ! Lorsque j'affecte o1 dans O1 puis le modifie par le serveur, j'ai 2 versions d'o1 dans mon programme client : c'est bien le nouveau dans le cache, mais O1 continue de pointer vers une ancienne version d'o1. Y a-t-il donc copie ? Où bien la référence n'est pas "centrale" et doit être mise à jour ?
    Pour assurer que je n'ai pas la berlue, ils portent tous les deux le MÊME nom (genre "mon.package.complet@12345ab") et sont pourtant DIFFÉRENTS.

    J'ai manifestement loupé quelque chose.
    Si vous avez une piste qui m'éclairerait, je suis preneur,

    Merci et bonne fin d'apm !

    ---
    Edit : heu, il faut que je vérifie un truc...

  2. #2
    Membre Expert
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Par défaut
    Ce n'est pas très clair, ton explication ...

    Tu pourrais donner un exemple plus détaillé, avec les serveurs et les objets qui contiennent ton "o1" ?

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Par défaut
    Salut,

    Bienvenue dans le monde Java

    Ce n'est pas très clair, ton explication ...
    En effet, certains points sont flous.

    Peux tu détailler l'architecture utilisée ?
    - ton client et ton serveur sont ils sur la même machine ?
    - comment communique t-il ? Par simple appel local ou via des appels réseaux (ex: RMI, EJB, Socket...)
    - ton appli et ton client constitue chacun une appli java différente ou c'est la même appli ?

    Si ton client et ton serveur ne tournent pas dans la même appli, donc la même JVM, les objets ne seront pas partager par les deux applis.
    Donc modif de l'un n'est pas visible pour l'autre.

    Si ils tournent dans la même appli mais que ton objet est à un moment sérialisé que cela soit du coté serveur ou client, il perdra son identité objet originel et tu te retrouvera donc avec deux instances différentes.


    Ainsi, l'objet o1 était envoyé au client pour alimenter un "objet client" de type O1(o1). Si le serveur modifiait o1, je pensais que le remplacement de l'ancien o1 par le nouvel o1 (o1.equals(o1) = true) dans le cache client suffisait à modifier dans le même temps le o1 référencé dans O1. Vous me suivez ?
    La je t'avoue que je t'ai perdu
    Je ne vois pas trop ce que tu entends par "modifiait o1". Si tu modifies un champ de l'objet serveur o1, la référence du client O1.o1 sera elle aussi affectée puisqu'elle pointe sur le même objet : o1 (à condition qu'il n'y est pas de sérialisation et même appli...)
    Maintenant, tu dois modifier les propriétés de o1 et surtout pas faire de new o1()). Sinon l'identité d'objet est cassé.

    Si tu es toujours bloqué, montre nous le code du cache ainsi que la façon dont le serveur modifie l'objet o1.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 93
    Par défaut
    Oui, toujours bloqué. Et c'est juste, je vais essayer d'être plus clair.

    Ma problématique : limiter l'encombrement mémoire du client en lui envoyant le minimum nécessaire à la navigation de l'utilisateur.

    Pour faciliter l'exposé, disons que j'ai des maisons qui contiennent des pièces, chacune contenant des meubles. Particularité : la base de données ne contient que les pièces et les meubles dérivées de la classe "composant". Les maisons, elles, sont construites par le client à partir de ces composants par l'intermédiaire d'une classe "Holder" d'où sont dérivées pieceHolder et meubleHolder.

    En code, ça donne par exemple :
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public class Maison {
    	Set<Piece> pieces ;
     
    	public Maison(Set<Piece> pieces) {
    	this.pieces = pieces ;
    	}
    }
     
    public class Piece extends Composant implements Serializable {
    	Set<Meuble> meubles ;
     
    	public Piece(Set<Meuble> meubles) {
    	this.meubles = meubles ;
    	}
    }
     
    public class Meuble() extends Composant implements Serializable {
    	Set<Meubles> meubles ; // Il peuvent s'imbriquer.
     
    	public meubles(Set<Meuble> meubles {
    	this.meubles = meubles ;	
    	}
    }
     
    public class Holder {
    	Composant composant ;
     
    	public Holder(Composant composant) {
    	     this.composant = composant ;
    	}
    }
     
    public class pieceHolder extends Holder {
    	     public pieceHolder(Piece piece) {
    	     super(piece) ;
    	}
    }
    public class meubleHolder extends Holder {
    	     public meubleHolder(Meuble meuble) {
    	     super(meuble) ;	
    	}
    }
    Plus un utilisateur s'approche d'une maison, plus je dois la "remplir" de ses attributs.

    Pour ce faire, le client (appli java) et le serveur (autre appli java) communiquent par socket (donc sérialisation), et utilisent pour leurs transferts une classe identique "Cache" listant les composants.

    Note 1 : J'utilise concurremment un HashSet sur la classe parente "Composant" et un HashMap car j'ai besoin aussi d'un mode de parcours sur clé.
    Note 2 : Limite de mon schéma simplifié : chez moi, des pièces peuvent contenir les mêmes meubles, d'où la juxtaposition des Map (sinon, auraient évidemment été imbriqués).

    Voici le cache et la fonction d'actualisation utilisée par le client.
    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 class Cache() {
     
    	Set<Composant> composants = new HashSet<Composant>() ;
    	Map<Integer, Piece> pieces = new HashMap<Integer, Piece>() ;
    	Map<Integer, Meuble> meubles = new HashMap<Integer, meuble>() ;
     
    	/** Fonction de mise à jour du cache à partir d'un cache en provenance du serveur. */
    	public void updateCache(Cache nouveauCache) {
     
    		// Cette double boucle est-elle nécessaire ? La fonction add() du 
                    // HashSet évite les doublons, mais n'effectue visiblement pas de 
                    // remplacement.  
    		for(Composant c1 : nouveauCache.composants)
                             for(Composant c2 : this.composants)
                                    if(c1.equals(c2)) c2 = c1 ; // Ça, ça fonctionne.
     
            // Retire tous les anciens éléments à mettre à jour, sinon pas de modification.
            cache.removeAll(nc.cache) ;
            // Ajoute les éléments mis à jour.
            cache.addAll(nc.cache); // Ça fonctionne.
     
            // Pour le Map, par contre, il semble que le remplacement soit
            // "automatique" par "put" dans un HashMap. Et l'affectation a 
            // déjà été opérée dans la première boucle.
     
            pieces.putAll(nouveauCache.pieces) ; // Ok.
            meubles.putAll(nouveauCache.meubles) ; // Ok.
    	}
    }
    J'ai ensuite une classe HolderManager qui affecte les pièces et les meubles dans les Holders à partir du cache reçu.
    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
    public class HolderManager {
     
    	/** Le HashMap sert d'index composant - Holder */
    	private HashMap<Composant, Holder> hashHolder  = new HashMap<Composant, Holder>() ;
     
    	public void setHolder(Cache cache) {
     
            for(Composant c : cache.composants) {
     
            // Des éléments pré-existant peuvent revenir dans le cache après avoir
            // été modifiés dans le serveur. Il faut donc s'assurer qu'ils n'ont pas
            // déjà un Holder pour le conserver et éviter de perdre l'assemblage
            // existant.
                if(!this.hashHolder.containsKey(c)) {
                    if(c instanceof Piece) {
                        PieceHolder pieceHolder = new pieceHolder(c) ;
                        this.hashHolder.put(piece, pieceHolder) ;
                    } else if(c instanceof Meuble) {
                        meubleHolder meubleHolder = new MeubleHolder(c) ;
                        this.hashHolder.put(meuble, meubleHolder) ;
                    }
                }
            }
         }
    }
    Voilà. Donc par conséquent, lors de la première navette, j'ai construit un lot de maisons, disons avec des pièces, mais sans les meubles. L'utilisateur se rapproche, et le client demande un complément d'information. Le serveur récupère les pièces qu'il a lui-même gardé en mémoire (il conserve une copie du cache transféré, ce sont donc a priori les mêmes objets), et les remplit de leurs meubles. Les pièces ainsi complétées reviennent par un cache, et le cache du client est actualisé par la fonction updateCache().

    Ce remplacement-là fonctionne. Dans le cache du client, les pièces contiennent les nouveaux meubles.

    MAIS PAS DANS LES HOLDERS !! où les pièces restent vides !!
    Comprends pas pourquoi !

    Help !

    P.S. : Je précise que j'ai défini un hashCode() et un equals() à ma sauce pour la classe composant, afin de ne pas être influencé par l'ajout de meubles dans les pièces.

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Par défaut
    Ce remplacement-là fonctionne. Dans le cache du client, les pièces contiennent les nouveaux meubles.

    MAIS PAS DANS LES HOLDERS !! où les pièces restent vides !!
    1.Je suis pas sur d'avoir compris l'étape de mise à jour.
    Le client appelle updateCache(Cache nouveauCache). Ensuite tu fais appel a la classe HolderManager pour créer les holders correspondant aux composants du nouveau cache. Est ce que c'est bien ca ?

    2.Si c'est bien ça, cette partie de la méthode setHolder(Cache) de la classe HolderManager m'étonne un peu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      if(!this.hashHolder.containsKey(c)) {
                    if(c instanceof Piece) {
                        PieceHolder pieceHolder = new pieceHolder(c) ;
                        this.hashHolder.put(piece, pieceHolder) ;
                    } else if(c instanceof Meuble) {
                        meubleHolder meubleHolder = new MeubleHolder(c) ;
                        this.hashHolder.put(meuble, meubleHolder) ;
                    }
                }

    J'ai sûrement pas tout compris comme je n'ai qu'une partie du code et des explications, mais dans cette méthode, tu ajoutes au holder le composant uniquement si il la pièce ou meuble n'est pas dans la HashMap. Or, imaginons que la pièce fournit par le cache ait changé, elle n'est plus vide désormais.Etant donné que ta méthode equals ne prends pas en compte les meubles, l'instruction
    this.hashHolder.containsKey(c)
    retournera true et le holder n'ajoutera pas la version modifiée de la pièce.
    La pièce sera donc toujours vide pour le holder.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    93
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 93
    Par défaut
    Citation Envoyé par thebloodyman Voir le message
    1.Je suis pas sur d'avoir compris l'étape de mise à jour.
    Le client appelle updateCache(Cache nouveauCache). Ensuite tu fais appel a la classe HolderManager pour créer les holders correspondant aux composants du nouveau cache. Est ce que c'est bien ca ?
    C'est ça.
    Pour clarifier encore ce qui pourrait l'être :
    Le serveur a son propre Cache, "serveurCache".
    Le client a son propre Cache, "clientCache".
    Et les deux échangent un Cache, "transfertCache".

    C'est-à-dire que lors de la première arrivée d'un transfertCache (nommé "nouveauCache" dans l'exemple donné) dans le client,
    1) les composants sont versés dans le cacheClient.
    2) puis dans la foulée sont affectés dans des holders créés pour eux.
    À ce moment-là, donc, que ce soit dans le cacheClient et les Holders, s'y trouvent les mêmes objets.

    Maintenant, si je modifie un composant, je ne veux pas créer un nouveau Holder, mais simplement lui substituer la nouvelle version de son composant à l'ancienne.

    Par conséquent, quelque part dans mon code - en l'occurence lors de l'updateCache - j'affecte la nouvelle valeur à l'ancienne.
    Puisque c'est la même référence dans les holders, je m'attendais à ce qu'elle soit modifiée en même temps.
    2.Si c'est bien ça, cette partie de la méthode setHolder(Cache) de la classe HolderManager m'étonne un peu :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      if(!this.hashHolder.containsKey(c)) {
                    if(c instanceof Piece) {
                        PieceHolder pieceHolder = new pieceHolder(c) ;
                        this.hashHolder.put(piece, pieceHolder) ;
                    } else if(c instanceof Meuble) {
                        meubleHolder meubleHolder = new MeubleHolder(c) ;
                        this.hashHolder.put(meuble, meubleHolder) ;
                    }
                }
    J'ai sûrement pas tout compris comme je n'ai qu'une partie du code et des explications, mais dans cette méthode, tu ajoutes au holder le composant uniquement si il la pièce ou meuble n'est pas dans la HashMap. Or, imaginons que la pièce fournit par le cache ait changé, elle n'est plus vide désormais.Etant donné que ta méthode equals ne prends pas en compte les meubles, l'instruction retournera true et le holder n'ajoutera pas la version modifiée de la pièce.
    C'est juste, oui.

    Le HashMap n'est qu'un index. Mais sa construction me sert à connaître les holders qui existent déjà, et à générer ceux qui correspondent à de nouveau composants.
    Je ne veux pas créer de nouveau holder pour un composant qui existe déjà, car le holder est à ce moment-là déjà disséminé et agissant dans tout le code de l'appli). Il est censé pouvoir prendre en compte la modification progressivement.
    La pièce sera donc toujours vide pour le holder.
    Ben... il m'avait semblé comprendre que la référence n'est qu'une adresse du DOM. Si je modifie, à partir du cacheClient, le contenu d'une même adresse / i.e. d'un objet pointé par un holder, n'est-il pas censé automatiquement prendre les nouvelles valeurs ? (toutes les opérations décrites se déroulent chez le client, j'insiste là-dessus).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [FLASH 8] Question sur la portée des objets.
    Par i_shinji dans le forum Flash
    Réponses: 1
    Dernier message: 02/11/2005, 17h18
  2. [DEBUTANT] Conseil sur la programmation orienté objet
    Par etiennegaloup dans le forum Langage
    Réponses: 7
    Dernier message: 27/05/2005, 12h59
  3. [Struts] <logic:iterate> sur une collection d objets c
    Par trax020 dans le forum Struts 1
    Réponses: 2
    Dernier message: 12/05/2005, 00h11
  4. Question simple sur la libération des objets
    Par gibet_b dans le forum Langage
    Réponses: 2
    Dernier message: 12/07/2004, 10h01

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