web-dev-qa-db-fra.com

Les méthodes d'une classe doivent-elles appeler ses propres getters et setters?

Là où je travaille, je vois beaucoup de classes qui font des choses comme ça:

public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}

Si j'avais écrit cela à partir de zéro, j'aurais écrit la methodWithLogic() comme ceci à la place:

public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}

Je pense que lorsque la classe appelle ses propres getters et setters, cela rend le code plus difficile à lire. Pour moi, il est presque implique que la logique complexe se produit dans cet appel de méthode, même si dans notre cas, il ne l'est presque jamais. Lorsque je débogue un code inconnu, qui peut dire que le bogue n'est pas un effet secondaire dans cette méthode? En d'autres termes, cela me fait faire beaucoup de détournements pour comprendre le code.

La première méthode présente-t-elle des avantages? La première méthode est-elle réellement meilleure?

53
Daniel Kaplan

Je ne dirai pas ce qui est meilleur ou pire, car cela dépend en partie de votre situation (à mon avis). Mais considérez que vos getters et setters peuvent changer d'implémentation plus tard, et les contourner ignorerait cette logique.

Par exemple, que se passe-t-il si vous ajoutez un indicateur "sale" à certains champs de définition plus tard? En appelant vos setters dans votre code interne, vous définissez le drapeau sale sans changer aucun autre code. Dans de nombreuses situations, ce serait une bonne chose.

46
Matt S

Appeler directement le passeur n'est pas, en soi, un problème. La question devrait vraiment être: pourquoi notre code a-t-il des setters partout?

Les classes mutables sont un jeu dangereux, en particulier lorsque la classe elle-même gère son propre état. Considérez combien de ces colons ont vraiment besoin d'exister. Combien pourraient être définis dans le constructeur et ensuite être encapsulés entièrement par la classe elle-même?

Si le champ doit être paramétrable en externe, demandez-vous si la méthode avec logique doit être là. Votre classe elle-même est-elle vraiment juste une classe data/state? Cette classe a-t-elle plus d'une responsabilité?

Ne vous méprenez pas, il y aura des cas où ça ira. Je ne dis pas que vous devez éliminer complètement les setters sur les classes avec logique. Mais cela devrait être l'exception, pas la règle. Et, dans ces quelques cas, il devrait être évident auquel accéder directement.

33
pdr

Oui, les méthodes de votre classe devraient appeler les getters et setters. L'intérêt de l'écriture des getters et setters est la pérennité. Vous pouvez faire de chaque propriété un champ et exposer directement les données aux utilisateurs de la classe. La raison pour laquelle vous construisez les getters et setters n'est pas nécessairement parce qu'il y a une logique complexe maintenant mais pour que l'interface ne se casse pas à l'avenir si vous devez l'ajouter.

9
Michael

Pour répondre à vos questions en un seul mot, oui.

Le fait qu'une classe appelle ses propres getters et setters ajoute de l'extensibilité et fournit une meilleure base pour le futur code.

Disons que vous avez quelque chose comme ça:

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

Appeler les setters pour year et make actuellement n'ajoute aucune fonctionnalité, mais que se passe-t-il si vous voulez ajouter quelque chose comme la validation d'entrée aux setters?

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}
6
Zach Latta

Une chose qui n'a pas été mentionnée est que le getter et les setters (comme toutes les méthodes) sont virtuels en Java. Cela ajoute une autre fonctionnalité pour toujours les utiliser dans votre code. Un autre utilisateur pourrait étendre votre classe, écrasant vos getters et setters. Votre classe de base utiliserait alors les données de la sous-classe au lieu des siennes. Dans un langage où vous marquez explicitement des fonctions virtuelles, cela est beaucoup plus pratique car vous pouvez prédire et déclarer avec quelles fonctions cela peut être fait. En Java, c'est quelque chose dont vous devez toujours être conscient. Si c'est un comportement souhaité, les utiliser dans votre code est une bonne chose, sinon pas tant.

5
Jonathan Henson

Si vous essayez d'accomplir quelque chose qui est fourni par l'interface publique, utilisez les getters/setters.

Cependant, en tant que propriétaire/développeur de la classe, vous êtes autorisé à accéder aux sections privées de votre code (depuis la classe bien sûr), mais vous êtes également responsable de l'atténuation des dangers.

Donc, vous avez peut-être un getter qui itère sur une liste interne et vous voulez obtenir la valeur actuelle sans incrémenter l'itérateur. Dans ce cas, utilisez la variable privée.

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}
3
ConditionRacer

Je dirais non ..

Si vos getters/setters obtiennent juste et définissent (pas d'initialisation paresseuse, pas de vérifications, etc.) alors utilisez simplement vos variables. Si à l'avenir vous changez vos getters/setters, vous pouvez très bien changer votre methodWithLogic() (parce que c'est votre classe qui change) et vous pouvez appeler un getter/setter au lieu d'une affectation directe. Vous pouvez documenter cet appel pour le getter/setter (car il sera étrange d'appeler un getter/setter lorsque le reste de votre code de classe utilise directement la variable).

La JVM alignera les appels fréquents aux getters/setters. Donc, ce n'est jamais un problème de performances. Le gain de l'utilisation de variables est la lisibilité et à mon humble avis, j'irais pour cela.

J'espère que cela t'aides..

1
Pravin Sonawane

Oui. Les getters et les setters représentent l'état, alors retournez cette question - voulez-vous avoir à garder une trace de plusieurs façons de changer l'état d'un objet de la même manière, sauf si vous le devez?

Moins vous avez de choses à faire, mieux c'est - c'est pourquoi les objets immuables sont plus faciles à gérer.

Considérez, rien ne vous empêche d'avoir à la fois un domaine public et un getter/setter public - mais que gagneriez-vous?

Il peut parfois être souhaitable ou même nécessaire d'accéder directement au champ pour une ou plusieurs raisons, vous ne devriez pas vous dérober si cela se produit. Mais vous ne devriez vraiment le faire que s'il y a un avantage défini à le faire.

1
jmoreno

Les deux méthodes ont leurs cas d'utilisation. Comme le setter public maintient la valeur du champ (et/ou les valeurs liées) cohérente, vous devez utiliser setter lorsque votre logique de méthode n'interfère pas avec cette logique de cohérence. Si vous venez de définir votre "propriété", utilisez setter. D'un autre côté, il y a des situations où vous avez besoin d'un accès direct à certains champs, par exemple des opérations en bloc avec setter lourd ou des opérations où le concept de setter est trop simple.

Il est de votre responsabilité de garder les choses cohérentes. Setter le fait par définition, mais ne peut pas couvrir des cas complexes.

1
Artur