Question

    

Cette question a déjà une réponse ici:

         

Je travaille actuellement sur un jeu simple en Java avec plusieurs modes différents. J'ai étendu une classe principale du jeu pour mettre la logique principale dans les autres classes. Malgré cela, la classe principale du jeu est encore assez lourde.

Après avoir pris un coup d'oeil à mon code la majorité de celui-ci était accesseurs (60%) par rapport au reste qui est vraiment nécessaire pour la logique du jeu.

Quelques recherches Google ont affirmé que Getters et Setters sont mal, tandis que d'autres ont affirmé qu'ils sont nécessaires pour une bonne pratique de OO et de grands programmes.

Alors, que dois-je faire? Qui devrait-il être? Dois-je changer mes accesseurs et de mutateurs pour mes variables privées, ou devrais-je rester avec eux?

Était-ce utile?

La solution

Il est aussi le point de vue que la plupart du temps, en utilisant setters brise encore l'encapsulation en vous permettant de définir les valeurs qui sont sans signification. A titre d'exemple très évident, si vous avez un compteur de score sur le jeu qui ne va que jamais, au lieu de

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

il devrait être

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

Ceci est peut-être un peu d'un exemple facile. Ce que je veux dire est que la discussion getter / setters vs champs publics obscurcit souvent plus gros problèmes avec des objets manipuler l'état interne de chacun d'une manière intime et étant donc trop étroitement couplée.

L'idée est de faire des méthodes qui font des choses directement que vous voulez faire. Un exemple serait comment définir le statut « vivant » d'ennemis. Vous pourriez être tenté d'avoir une méthode setAlive (booléenne vivant). Au lieu de cela, vous devriez avoir:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

La raison est que si vous modifiez la mise en œuvre que les choses ne sont plus un booléen « vivant », mais plutôt une valeur « frapper des points », vous pouvez changer cela autour sans rompre le contrat des deux méthodes que vous avez écrit plus tôt:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }

Autres conseils

  • Très mal. Champs publics
  • Un peu mal. Accesseurs où ils ne sont pas requis
  • Bon: accesseurs seulement où ils sont vraiment nécessaires - faire le type d'exposer le comportement « plus » qui arrive à utiliser son état, plutôt que de simplement traiter le type de dépôt de l'Etat à être manipulé par d'autres types.

Cela dépend vraiment de la situation si - parfois vous vraiment faire veulent tout simplement un objet de données muet

.

Vous avez déjà eu beaucoup de bonnes réponses à ce sujet, donc je vais vous donner mes deux cents. Accesseurs sont très, très mal. Ils laissent essentiellement que vous prétendez cacher votre internals de l'objet lorsque la plupart du temps tout ce que vous avez fait est jeté dans le code redondant qui ne fait rien pour cacher l'état interne. Pour un POJO simple, il n'y a aucune raison pour getName () et setName () ne peut pas être remplacé par obj.name = "Tom".

Si l'appel de méthode remplace simplement l'affectation, tout ce que vous avez gagné en préférant l'appel de méthode est météorisation code. Malheureusement, la langue a consacré l'utilisation des accesseurs dans la spécification JavaBeans, donc les programmeurs Java sont contraints de les utiliser, même si cela fait donc aucun sens.

Heureusement, Eclipse (et probablement d'autres environnements de développement, ainsi) vous permet de les générer automatiquement. Et pour un projet amusant, je une fois construit un générateur de code pour eux en XSLT. Mais s'il y a une chose que je voudrais me débarrasser de Java, son de la dépendance excessive aux accesseurs.

accesseurs appliquer le concept d'encapsulation dans la programmation orientée objet.

En ayant les états de l'objet caché du monde extérieur, l'objet est vraiment en charge elle-même, et ne peut être modifié d'une manière qui ne sont pas destinés. Les seuls moyens de l'objet peut être manipulé par des méthodes sont publiques exposées, telles que des accesseurs.

Il y a quelques avantages pour avoir des accesseurs:

1. Permettre des changements futurs sans modification de code qui utilise la classe modifiée.

L'un des gros avantage d'utiliser un getter et setter est qu'une fois que les méthodes publiques sont définies et il arrive un moment où la mise en œuvre sous-jacente doit être modifiée (par exemple la recherche d'un bug qui doit être corrigé, en utilisant un algorithme différent pour améliorer la performance, etc.), en ayant les accesseurs être la seule façon de manipuler l'objet, il permettra le code existant pour ne pas casser, et le travail comme prévu, même après le changement.

Par exemple, disons qu'il ya une méthode setValue qui définit la variable privée value dans un objet:

public void setValue(int value)
{
    this.value = value;
}

Mais alors, il y avait une nouvelle exigence qui avait besoin de garder une trace du nombre de fois value a été changé. Avec le poseur en place, le changement est assez trivial:

public void setValue(int value)
{
    this.value = value;
    count++;
}

Si le champ value étaient publiques, il n'y a pas moyen facile de revenir plus tard et ajouter un compteur qui garde la trace du nombre de fois que la valeur a été modifiée. Par conséquent, ayant des accesseurs sont un moyen de « l'épreuve du futur » de la classe pour les changements qui peuvent venir plus tard.

2. Appliquer les moyens par lesquels l'objet peut être manipulé.

Une autre façon accesseurs sont utiles est de faire respecter les façons l'objet peut être manipulé, par conséquent, l'objet est dans le contrôle de son propre état. Avec des variables publiques d'un objet exposé, il peut facilement être endommagé.

Par exemple, un objet ImmutableArray contient un tableau de int appelé myArray. Si le tableau était un champ public, juste ne sera pas immuable:

ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.

Pour mettre en œuvre un ensemble vraiment immuable, un getter pour la matrice (méthode getArray) doit être écrit de sorte qu'il retourne une copie de son tableau:

public int[] getArray()
{
    return myArray.clone();
}

Et même si ce qui suit se produit:

ImmutableArray a = new ImmutableArray();
int[] b = a.getArray();
b[0] = 10;      // No problem, only the copy of the array is affected.

Le ImmutableArray est en effet immuable. Exposer les variables d'un objet permettra d'être manipulé d'une manière qui ne sont pas destinés, mais seulement d'exposer certaines façons (accesseurs), l'objet peut être manipulé de manière prévues.

Je suppose avoir des accesseurs seraient plus importants pour les classes qui font partie d'une API qui va être utilisé par d'autres, car elle permet de maintenir l'API intacte et inchangée, tout en permettant des changements dans la mise en œuvre sous-jacente.

Avec tous les avantages des accesseurs dit, si le getter est simplement retourne la valeur de la variable privée et le poseur est simplement d'accepter une valeur et l'assigner à une variable privée, il semble que les getters et régleurs sont tout simplement étrangers et vraiment une perte. Si la classe va être juste pour un usage interne par une application qui ne va pas être utilisé par d'autres, en utilisant des accesseurs peuvent ne pas être largement aussi important que lors de l'écriture d'une API publique.

Ils sont tout à fait mal.

@coobird malheureusement ils ne sont pas tout à fait « appliquer le concept d'encapsulation », tout ce qu'ils font est que vous faites que vous encapsulant les données alors qu'en fait vous exposer les données via une propriété avec la folie des grandeurs de la méthode. Tout ce qu'un getter / setter fait un champ public fait mieux.

Tout d'abord, si vous voulez que les données publiques, le rendre public, se débarrasser des méthodes getter et setter pour réduire le nombre de méthodes, le client doit parcourir et de le rendre cognitivement plus simple pour le client de changer sa valeur par exemple.

object.field = value;

au lieu de plus cognitivement intense

object.setField(value);

où le client doit maintenant vérifier la méthode getter / setter pour voir si elle a des effets secondaires.

Deuxièmement, si vous avez vraiment besoin de faire quelque chose d'autre dans la méthode, pourquoi appeler une méthode get / set quand il a plus de responsabilités que simplement obtenir ou définir? Soit suivre la SRP ou appeler la méthode quelque chose qui vous indique en fait ce que le ensemble méthode fait comme les exemples de Zarkonnen dont il a parlé par exemple.

public void kill(){
    isAlive = false;
    removeFromWorld(this);
}

au lieu de

public void setAlive(boolean isAlive){
    this.isAlive = isAlive;
    if (isAlive)
        addToWorld(this);
    else
        removeFromWorld(this);
}

où est la méthode setAlive (booléenne) dire au client que comme un effet secondaire, il va supprimer l'objet du monde? Pourquoi le client doit avoir des connaissances sur le terrain isAlive? De plus ce qui se passe lorsque l'objet est à nouveau ajouté au monde, devrait-il être réinitialisée? pourquoi le soin client de tout cela?

à mon humble avis est la morale aux méthodes de nom pour dire exactement ce qu'ils font, suivez la SRP et de se débarrasser des getters / setters. S'il y a des problèmes sans getters / setters, dire des objets à faire leur propre travail sale à l'intérieur de leur propre classe au lieu d'essayer de faire des choses avec eux dans d'autres classes.

ici endeth mes coups de gueule, désolé;)

Il est une pente glissante.

Un simple objet de transfert (ou un objet de paramètres) peuvent avoir le seul but de tenir des champs et de fournir leurs valeurs sur demande. Cependant, même dans ce cas dégénéré on pourrait dire que l'objet doit être immuable -. Configuré dans le constructeur et l'exposition ne get ... méthodes

Il y a aussi le cas d'une classe qui expose des « boutons de commande »; votre interface utilisateur de autoradio peut probablement être comprise comme exposant quelque chose comme getVolume, setVolume, getChannel et setChannel, mais sa fonctionnalité réelle reçoit des signaux et émettre un son. Mais ces boutons ne pas exposer plus de détails de mise en œuvre; vous ne savez pas de ces fonctions d'interface si la radio est, pour la plupart des transistors-logiciels, ou des tubes à vide.

Plus vous commencez à penser à un objet en tant que participant actif dans une tâche problème domaine, plus vous penserez en termes de lui demander de faire quelque chose au lieu de lui demander de dire vous de son état interne, ou de demander pour ses données si autre code peut faire quelque chose avec ces valeurs.

Alors ... "mal"? Pas vraiment. Mais chaque fois que vous avez tendance à mettre en valeur et d'exposer à la fois get ... et set ... méthodes de cette valeur, demandez-vous pourquoi, et ce que la reponsibility de cet objet est vraiment. Si la seule réponse que vous pouvez vous donner est, « Pour maintenir cette valeur pour moi », puis peut-être quelque chose en plus OO se passe ici.

Votre classe de jeu est probablement le suit antimodèle si elle expose que de nombreuses variables. Il n'y a rien de mal avec des accesseurs (bien que leur verbosité en Java peut être un peu gênant); dans une application bien conçue où chaque classe a une fonctionnalité clairement séparée, vous aurez pas besoin des dizaines d'entre eux dans une seule classe.

Modifier Si le point principal pour les accesseurs est de « configurer » le jeu classe (je comprends votre commentaire de cette façon), votre probablement pas besoin les getters (il est parfaitement très bien pour une classe pour accéder à ses propres variables privées sans utiliser les méthodes get), et vous pouvez probablement beaucoup l'effondrement des setters en « faiseurs de groupe » qui a défini plusieurs variables qui appartiennent ensemble sur le plan conceptuel.

La présence de getter et setters tend à indiquer (une « odeur » si vous êtes dans ce genre de langue à l'école primaire) qu'il ya un problème de conception. getters triviales et setters se distinguent à peine des champs publics. En règle générale le code d'exploitation des données sera dans une autre classe -. Encapsulation pauvres, et ce que vous attendez des programmeurs pas à l'aise avec OO

Dans certains cas accesseurs sont très bien. Mais en règle générale, un type avec les deux accesseurs indique des problèmes de conception. Getters travaillent pour immuabilité; setters travaillent pour « dire ne demandez pas ». Les deux immuabilité et « disent ne demandent pas » sont de bons choix de conception, tant qu'ils ne sont pas appliqués dans un style qui se chevauchent.

Mon opinion est que accesseurs sont une exigence de bons programmes. Stick avec eux, mais ne pas écrire getters / setters inutiles -. Il est pas toujours nécessaire de traiter directement avec toutes les variables

Je ne pense pas qu'ils sont mauvais. Mais j'aimerais vivre dans un monde où je ne devais les utiliser à moins que je devais vraiment.

Un exemple que je lis ci-dessus était future-proofing votre code. Par exemple:

public void setValue(int value)
{
    this.value = value;
}

Ensuite, les besoins changent et vous avez besoin de savoir combien de fois la valeur a été réglée.

public void setValue(int value)
{
    this.value = value;
    count++;
}

Ceci est beau. J'ai compris. Cependant, Ruby, serait le suivant sert pas le même but?

someobject.my_value = 100

Plus tard, vous devez suivre le nombre de fois my_value a été fixé. Eh bien, pourriez-vous pas seulement remplacer le setter puis et que ALORS ?

def my_value=(value)
    @my_value = value
    @count++
end

Je suis tout à beau code, mais je dois admettre que, en regardant à travers les montagnes des classes Java que nous avons et de voir des milliers et des milliers de lignes de code qui ne sont que getter de base / setters est laid et ennuyeux.

Quand je développais à temps plein C #, nous avons utilisé les propriétés publiques tout le temps et fait getters / setters personnalisés uniquement en cas de besoin. Travaillé comme un charme et il ne casse rien.

Comme toujours la seule réponse est: cela dépend. Si vous êtes le seul Perón touchant le code, vous pouvez faire tout ce que vous êtes à l'aise avec, y compris les raccourcis de prise.

L'un des avantages de l'utilisation setters est que les contrôles doivent être effectués à un seul emplacement dans votre code.

Vous voudrez peut-être payer un peu plus d'attention à ce qui est réellement et ECRIRE par ces méthodes. Si vous les utilisez pour fournir un accès à des valeurs constantes que vous êtes probablement mieux en utilisant des constantes.

Cela dépend du langage de programmation en question. Votre question est formulée dans le contexte de Java, où il semble que des accesseurs sont généralement considérés comme une bonne chose.

En revanche, dans le monde Python, ils sont généralement considérés comme mauvais style: ils ajoutent des lignes au code sans y ajouter des fonctionnalités réellement. Lorsque les programmeurs Python doivent, ils peuvent utiliser metaprogramming pour attraper obtenir et / ou le réglage des attributs d'objet.

En Java (la version de Java que j'ai appris au moins un peu il y a dix ans), qui n'a pas été possible. Ainsi, en Java, il est généralement préférable d'utiliser des accesseurs religieusement, de sorte que si vous avez besoin, vous pouvez remplacer l'accès aux variables.

(Cela ne fait pas nécessairement Python mieux que Java, juste différent.)

Juste Pour votre information: En plus de toutes les excellentes réponses dans ce fil, rappelez-vous de toutes les raisons pour lesquelles vous pouvez venir avec pour ou contre getters / setters, les performances ne sont pas un (comme certains pourraient le croire). La machine virtuelle Java est assez intelligent pour inline getters / setters trivial (même les non-final, tant qu'ils ne sont pas réellement surchargées).

Vous pouvez remplacer certaines de vos classes en classes de valeurs. Cela vous permettra de supprimer le getter et éviter les problèmes lorsque le contenu est changé sous vous.

Si vous avez besoin d'un accès externe aux valeurs individuelles des champs, utilisez getters et / ou setters. Dans le cas contraire, ne pas. Ne jamais utiliser les champs publics. C'est aussi simple que ça! (Ok, il est jamais que simple, mais il est une bonne règle de base).

En général, vous devriez également trouver que vous devez fournir un setter beaucoup moins souvent qu'un getter - surtout si vous essayez de faire vos objets immuables - ce qui est une bonne chose (mais pas toujours le meilleur choix) - mais même sinon.

J'ai été la programmation en Java il y a quelques mois, et je l'ai appris que nous devrions utiliser getters et setters seulement quand il est nécessaire pour l'application

vous amuser:)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top