En java, que signifie exposer le représentant?


"Exposer le représentant" d'un objet peut être causé par lequel des éléments suivants:

  1. Ne pas déclarer les variables de sa classe comme privées.
  2. Permettant à une variable de l'objet de faire référence à un objet passé à c'est un argument pour son constructeur.
  3. Permettant de référence stockée dans une variable de l'objet à passé comme valeur de retour d'une méthode appelée sur cet objet.
  4. Tout ce qui précède.

Je sais que la réponse est 4 mais je ne suis pas sûr pourquoi, ma compréhension de ce qui expose le représentant n'est pas complètement claire.

Edit: pour des réponses claires

Author: ruakh, 2014-03-19

1 answers

Je n'avais jamais entendu ce terme, alors je l'ai googlé. Cet article l'a expliqué très clairement:

Http://www.cs.newpaltz.edu/~pletcha/oop_chap5_1.html

Exposer le représentant signifie violer la règle selon laquelle les méthodes d'un objet contrôlent son état. Par exemple, si un objet a des variables d'instance et des mutateurs pour changer leurs valeurs, puis l'objet a un moyen de contrôler son état. Si j'appelle foo.setBar(5), alors foo.getBar() mieux retourner 5 si la documentation dit getBar renvoie la valeur définie par setBar.

Je vais vous expliquer pourquoi chacune des trois descriptions que vous avez données expose la représentation d'un objet (ou plus généralement, casse l'encapsulation):

Ne pas déclarer les variables de sa classe comme privées.

Celui-ci est le plus facile. Si les variables d'instance sont publiques, tout ce qui se trouve dans la JVM peut changer leurs valeurs en dehors du code dans le même objet/classe. Si nous appelons foo.setBar(5), puis foo.getBar(), nous pouvons obtenir quelque chose d'autres que 5 parce que bar est une portée publique, donc une autre zone de code pourrait l'avoir muté.

Permettant une variable dans l'objet la référence à un objet passé en argument à son constructeur.

Celui-ci m'a pris une minute pour comprendre, mais cela a du sens si vous pensez à un objet et à ses dépendances comme une seule unité.

Si Foo est un Bar et Bar a int, appelé x, puis Foo pouvez le voir et le contrôle de la x bien sur bar parce qu'il a une référence. Si je crée une instance de Foo et passe une référence à une instance de Bar dans le constructeur de Foo, cela donne l'apparence que Foo a un contrôle complet. Mais il ne le fait pas. Exemple:

public class Foo {
    private Bar bar;

    public Foo(Bar bar) {
        this.bar = bar;
    }

    // immutable property - can only be read once this object is instantiated
    public Bar getBar() {
        return this.bar;
    }
}

public class Bar {
    private int x;

    public Bar(int x) {
        this.x = x;
    }

    public int getX() {
        return this.x;
    }

    public void setX(int x) {
        this.x = x;
    }
}

// some other java class
Bar bar = new Bar(10);
Foo foo = new Foo(bar);
bar.setX(5);

Ce code expose le représentant parce que foo a fait une hypothèse critique qu'il contrôle bar. Notez que sa référence à bar est immuable. Mais il n'est pas vraiment immuable. Seule la référence elle-même est immuable. Le code qui a créé foo a toujours un référence à bar et peut le muter sans que foo le sache.

Plus simplement, foo a une dépendance sur bar et la considère comme une partie de lui-même. Mais bar peut réellement changer indépendamment et donc l'état de foo a changé indirectement sans qu'il le sache.

Permettant une référence stockée dans une variable de l'objet à transmettre comme valeur de retour d'une méthode appelée sur l'objet.

Ceci est plus facile à expliquer par un collection.

public class Foo {
    private Collection<Bar> bars = new ArrayList<Bar>();

    // immutable property - can only be read once this object is instantiated
    public Collection<Bar> getBars() {
        return this.bars;
    }

    public void addBar(Bar bar) {
        this.bars.add(bar);
    }

    public int getBarCount() {
        return this.bars.size();
    }
}

Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount());  // -> 1

Cela viole le contrat. Pour ajouter une barre, vous devez appeler addBar. C'est pourquoi la méthode est exposée. En renvoyant une référence à la collection dans getBars, la collection sous-jacente peut être manipulée.

Cela semble trivial au premier abord. Mais si Foo fait cette règle et que l'utilisation ci-dessus la viole, alors que se passerait-il si je veux refactoriser {[12] } à cela (disons pour la performance):

public class Foo {
    private Collection<Bar> bars = new LinkedList<Bar>();
    private int barCount;  // for faster inserts, use a linked list and to maintain fast counts, track the count ourselves by tracking the adds.

    // immutable property - can only be read once this object is instantiated
    public Collection<Bar> getBars() {
        return this.bars;
    }

    public void addBar(Bar bar) {
        this.bars.add(bar);
        this.barCount++;
    }

    public int getBarCount() {
        return this.barCount;
    }
}

Foo foo = new Foo();
foo.getBars().add(new Bar(someUnexpectedBar));
System.out.println(foo.getBarCount());  // -> 0

Fonctionnellement, c'est identique. Si vous utiliser les méthodes de manière appropriée, il n'y aurait pas de différence. Mais nous avons triché. Nous avons saisi la collection sous-jacente et l'avons muté. Maintenant, la méthode getBarCount() renvoie la mauvaise réponse (0).

Le moyen de contourner cela est de retour une nouvelle collection avec un clone de l'original.

    public Collection<Bar> getBars() {
        return new ArrayList<Bar>(this.bars);
    }

Ou même

    public Collection<Bar> getBars() {
        return Collections.unmodifiableCollection(this.bars);
    }
 2
Author: Brandon, 2014-03-20 01:08:45