Question Les accesseurs sont-ils nécessaires lorsque les vars de terrain sont finaux?


en Java, c'est la convention (en ce qui me concerne) pour garder vos variables de champ privées et y accéder en utilisant des getters et / ou des setters. Cela vous permet de définir des règles pour modifier les valeurs des variables.

Mais que faire si les variables sont finales? Exemple:

public class Test {

    public final int MY_INT;

    public Test(int myInt) {
        MY_INT = myInt;
    }

}

Serait-ce permis? Il est compilé et fonctionne correctement, mais est-ce considéré comme un bon code?


11
2017-12-26 18:46


origine


Réponses:


Cela compile mais ce n'est pas considéré comme un bon code.

MY_INT viole la convention de nommage: les noms avec tous les calques sont utilisés pour static final variables, également appelées "constantes de classe" (voir ce et ce, Guide de style Java de Google aussi). pour se conformer aux conventions de nommage, il serait préférable de renommer myInt.

Il est recommandé de fournir un getter pour masquer les détails d'implémentation de votre classe. Les interfaces ne contiennent que des méthodes, pas des champs. Si vous laissez les autres classes se référer à ce champ par leur nom, alors vous perdez la liberté de changer le nom ou votre représentation interne plus tard.

Mais le plus important, les sous-classes ne peuvent pas remplacer les champs, elles ne peuvent que remplacer les méthodes. Si vous fournissez un getter à la place d'un champ, les sous-classes pourront remplacer cela et implémenter des comportements différents. Il serait donc préférable de fournir un getter et d’interdire l’accès direct au terrain lui-même.

(Grâce à @Sotirios Delimanolis pour les liens du guide de style de codage, très apprécié!)


16
2017-12-26 19:04



Si le client pouvait accéder au champ public de votre question avant qu’une valeur lui soit assignée (c’est-à-dire sans appeler le constructeur), il y aurait un problème évident. Plus précisément, ce champ ne pouvait pas avoir de valeur attendue lorsqu'un client tentait d'y accéder. Néanmoins, comme cela a été souligné dans les commentaires, vous n'avez pas déclaré Test.MY_INT avec un static identifiant, rendant pratiquement impossible la récupération de la valeur de cette constante sans appeler au préalable le constructeur.

Par conséquent, il semblerait judicieux (en termes d'immuabilité) de faire ce que vous faites. Cependant, en termes de «bon code», vous êtes (comme d’autres l’ont dit) obligeant vous-même et vos clients à vous référer explicitement à cette valeur par leur nom. Si vous utilisiez un getter, et que vous deviez changer le nom de MY_INT tout en conservant le même objectif, ni vous ni votre client ne serez obligé de changer quoi que ce soit au-delà de la mise en œuvre de Test.

Pour être plus explicite, je fournis à votre classe une constante et une privatisation constante.

public class Test {

    private final int MY_INT;

    public Test(int myInt) {
        MY_INT = myInt;
    }

    public int getAssignedIntValue() {
        return MY_INT;
    }

}

J'obtiendrais la valeur entière assignée comme ceci:

Test test = new Test(1);
// with your class
test.MY_INT;
// with the above class    
test.getAssignedIntValue();

Maintenant, dis que je renomme MY_INT à myInt pour correspondre aux conventions de dénomination. Dans les deux cas, je dois changer toutes les occurrences de MY_INT dans le Test classe. Mais, la différence entre les deux implémentations devient claire lorsque je dois obtenir la valeur avec le nouveau nom de constante:

// if this is the old code from above
Test test = new Test(1);
// I need to change this to test.myInt, or I get an ERROR!
test.MY_INT;
// since I didn't change the name of the getter, all is well
test.getAssignedIntValue();

Note: bien que cela ait pu être une réponse acceptable, elle n’a pas nécessairement le raisonnement le plus pertinent. S'il te plait regarde cette réponse pour le raisonnement donné dans un contexte plus général.


4
2017-12-26 18:53



Les réponses du fournisseur sont incomplètes (même celle sélectionnée comme "la réponse"). Considérez ce qui se passerait si le champ en question était une collection ou un tableau d'objets. C'est une bonne pratique de rendre TOUS les champs privés et de fournir des "getters" pour ces champs. Mais plus précisément, votre getter devrait renvoyer une référence (immuable) au champ (c.-à-d. String), OU une copie défensive de champs mutables (c'est-à-dire un tableau d'objets). En effet, même si vous ne pouvez pas modifier l'adresse de base de l'objet en question, vous pouvez modifier les paramètres internes de l'objet (tableau ou collection) en obtenant simplement l'adresse de base. Gardez à l'esprit que par champs mutables, je ne parle pas de tableaux ou de collections uniquement. Cela s'applique à toute classe mutable.

Revenons à la question, sont des getters CHAMPS OBLIGATOIRES? La réponse est non. TOUTEFOIS, si vous souhaitez avoir un code robuste, il est de votre intérêt de suivre ces meilleures pratiques; même si c'est juste pour créer de bonnes habitudes. Si vous ne les pratiquez pas régulièrement, vous ne suivrez pas les bonnes pratiques lorsque vous coderez (et il est fort probable que d’autres dans votre projet ne le feront pas non plus).


4
2017-12-26 20:37



Oui, vous pouvez. Tant que vous n'initialisez pas cette variable au niveau de la classe ou d'autres utilisateurs.


3
2017-12-26 19:01



Personnellement, je n'aime pas les champs publics à moins que votre classe ne soit qu'une classe de données. Votre classe est immuable, mais êtes-vous sûr de ne jamais vouloir le rendre mutable. Si un jour, pour une raison quelconque, vous avez besoin d’une copie mutable, il est plus facile d’avoir des copies mutables et immuables avec des getters et des setters.

Si vous avez des champs publics, les clients utiliseront vos champs dans leur code et vous ne pourrez pas changer leur nom à l'avenir.

Vous brisez l'encapsulation de cette façon.


3