2010-09-03 9 views
0

Je faisais un projet dans un livre Java et suis tombé sur cet exemple de code. L'auteur du livre a dit qu'au lieu d'initialiser directement X et Y dans mon constructeur, je pouvais appeler la méthode setLocation() de la classe à la place. Malheureusement, je n'ai plus le livre pour une explication concrète sur la raison pour laquelle c'est mieux. Je ne suis pas trop expérimenté avec Java mais n'est-il pas juste ... plus simple d'attribuer des valeurs directement et ne pas s'inquiéter d'un autre appel de fonction?Pourquoi appeler une méthode pour mieux définir les variables que de les définir normalement dans le constructeur?

//Point constructor, normal way of initializing variables 

private double x; 
private double y; 

Point(double initial_x, double initial_y) 
{ 
this.x = initial_x; 
this.y = initial_y; 
} 

//Point constructor, the other way 

Point(double initial_x, double initial_y) 
{ 
    setLocation(initial_x, initial_y); 
} 


public void setLocation(double newX, double newY) 
{ 
    this.x = newX; 
    this.y = newY; 
} 

Répondre

6

Je recommanderais en fait de ne pas appeler des setters dans un constructeur, car l'appel de méthodes redondantes depuis des constructeurs est une mauvaise idée. En outre, l'argument habituel pour les getters/setters est que la logique peut changer, et vous n'aurez pas à changer tout le monde qui accède à vos propriétés. Dans ce cas, cependant, si la logique change, les changements nécessaires sont limités à la même classe.

+0

Il est utile de savoir pourquoi @Adam est correct et que cette précaution est applicable à la fois pour C++ et Java/.Net: http://www.artima.com/forums/flat.jsp?forum=226&thread=113723 – rwong

+0

Ok, donc si une classe qui étend Point est créée et remplace setLocation() comment est-ce mauvais? Si la nouvelle classe appelle le constructeur de Point, Point n'appelle-t-il pas à son tour son propre setLocation() et évite-t-il tout mauvais comportement? – SDevil

+0

Je suis d'accord mais question :) Et si la logique au-delà de SetLocation faisait plus que simplement définir les propriétés ET devait se produire à chaque fois que l'objet a été créé? –

1

Parce que les deux instances sont privées vars dans quel exemple, le but de setLocation() dans ce contexte semble permettre à d'autres classes pour modifier les coordonnées de l'objet Point, après il a été initialisé. Et puisque le constructeur aurait fait effectivement la même chose (toujours pour cet exemple simple), le constructeur appelle simplement cette méthode par souci de simplicité.

0

Vous avez plus de contrôle sur le moment où ils sont réglés.

2

Même chose que tout le monde dit autre ci-dessus, avec une mise en garde supplémentaire:

, je pouvais voir un argument contre cette pratique si vous aviez besoin d'objets immuables, pour d'autres raisons ou la concurrence. Si vous faites quelque chose où plusieurs threads pourraient agir sur cet objet, le setter va probablement vous causer des ennuis.

0

S'il y a une certaine logique impliquée dans la définition des membres et que votre classe est mutable (en fournissant une méthode qui se comporte comme appeler le constructeur une seconde fois), il est logique d'utiliser une méthode d'initialisation.

private int width; 
private int height; 
private double diagonal; 

Image(int initial_w, int initial_h) 
{ 
Init(initial_w, initial_h) 
} 

public void Init(int initial_w, initial_h) 
{ 
width = initial_w; 
height = initial.h 
diagonal = Math.sqrt(width*width + height*height); // constructor doesn't need to repeat this line 
} 
0

Si x et y sont mutable et ont setters non triviales, puis en utilisant le dispositif de réglage pour les initialiser, même dans le constructeur, peut aider à éviter la duplication de code. Dans ce cas, vous pouvez marquer les setters comme final pour empêcher la possibilité qu'une classe dérivée remplace ces méthodes et provoque un comportement inattendu de votre constructeur.

Si les setters sont triviaux (affectation simple sans autre code), alors il n'y a pas beaucoup de raison d'utiliser le setter dans le constructeur.

Si les variables sont immuables, il vaut mieux ne pas avoir de setter du tout et les initialiser directement dans le constructeur.

+0

Si je veux empêcher une classe dérivée de surcharger une méthode, ne puis-je la déclarer privée? private void setLocation() {}; – SDevil

+0

@SDevil: Oui, mais un setter privé n'est généralement pas aussi utile qu'un public. Si vous avez une variable membre qui sera définie une seule fois par le constructeur et jamais plus, faites-la finale et définissez-la directement dans le constructeur. C'est une construction bien meilleure pour plusieurs raisons. – Eddie

-1

Cette ressource peut être utile:

http://en.wikipedia.org/wiki/JavaBean

J'ai personnellement constaté que les constructeurs ayant-arg simplifie pas l'injection de dépendance. Par exemple avec Spring IoC, alors que vous pouvez certainement spécifier des arguments constructeur, c'est beaucoup plus simple de ne pas avoir à le faire.

J'ai également trouvé que l'écriture de tests unitaires est plus simple pour la même raison que vous pouvez simplement instancier l'objet que vous voulez, injecter les propriétés requises pour les besoins de votre test et ensuite tester.Avoir un constructeur avec des arguments peut donc vous obliger à configurer les choses avec un objet que vous n'êtes pas particulièrement intéressé par les tests. Cela dit, fournir un constructeur sans argument n'est pas mutuellement exclusif pour fournir des constructeurs pratiques avec des arguments, c'est-à-dire que vous pouvez avoir les deux; assurez-vous simplement que vous disposez d'un système sans-argument pour répondre aux cas d'utilisation décrits ci-dessus.

+0

Le printemps a certainement ses problèmes. Mais quel est le point de tester un objet invalide? Peut-être que la classe en fait trop. –

+0

La plupart des frameworks DI sont plus faciles à configurer avec des beans, c'est-à-dire des classes avec des constructeurs sans argument. Je ne suis pas sûr de comprendre votre question, "Mais à quoi bon tester un objet invalide?". S'il vous plaît élaborer. –

Questions connexes