Je travaille sur un code d'interface utilisateur où j'ai une Action
classe, quelque chose comme ça -
public class MyAction extends Action {
public MyAction() {
setText("My Action Text");
setToolTip("My Action Tool tip");
setImage("Some Image");
}
}
Lorsque cette classe Action a été créée, il était à peu près supposé que la Action
classe ne serait pas personnalisable (dans un sens - son texte, son info-bulle ou son image ne seront modifiés nulle part dans le code). Maintenant, nous avons besoin de changer le texte de l'action à un certain endroit dans le code. J'ai donc suggéré à mon collègue de supprimer le texte d'action codé en dur du constructeur et de l'accepter comme argument, afin que tout le monde soit obligé de passer le texte d'action. Quelque chose comme ce code ci-dessous -
public class MyAction extends Action {
public MyAction(String actionText) {
setText(actionText);
setTooltip("My Action tool tip");
setImage("My Image");
}
}
Cependant, il pense que puisque la setText()
méthode appartient à la classe de base, elle peut être utilisée de manière flexible pour passer le texte d'action partout où l'instance d'action est créée. De cette façon, il n'est pas nécessaire de modifier la MyAction
classe existante . Donc, son code ressemblerait à quelque chose comme ça.
MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.
Je ne sais pas si c'est une bonne façon de régler le problème. Je pense que dans le cas mentionné ci-dessus, l'utilisateur va de toute façon changer le texte, alors pourquoi ne pas le forcer lors de la construction de l'action? Le seul avantage que je vois avec le code d'origine est que l'utilisateur peut créer une classe Action sans trop penser à définir du texte.
Réponses:
Ce n'est en fait pas un avantage, dans la plupart des cas, c'est un inconvénient et dans les autres cas, j'appellerais cela une égalité. Et si quelqu'un oublie d'appeler setText () après la construction? Et si tel est le cas dans un cas inhabituel, peut-être un gestionnaire d'erreurs? Si vous voulez vraiment forcer le texte à être défini, vous devez le forcer au moment de la compilation, car seules les erreurs au moment de la compilation sont réellement fatales . Tout ce qui se produit au moment de l'exécution dépend de l'exécution de ce chemin de code particulier.
Je vois deux voies claires en avant:
null
ou une chaîne vide, mais le fait que vous n'affectez pas de texte est explicite plutôt qu'implicite. Il est facile de voir l'existence d'unnull
paramètre et de voir qu'il y avait probablement une réflexion, mais pas si facile de voir l'absence d'un appel de méthode et de déterminer si l'absence d'un tel était intentionnel ou non. Pour un cas simple comme celui-ci, c'est probablement l'approche que j'adopterais.la source
La surcharge du constructeur serait une solution simple et directe ici:
Il vaut mieux que d'appeler
.setText
plus tard, car de cette façon, rien n'a besoin d'être écrasé,actionText
peut être la chose prévue dès le début.Au fur et à mesure que votre code évolue et que vous aurez besoin de plus de flexibilité (ce qui arrivera sûrement), vous bénéficierez du modèle d'usine / constructeur suggéré par une autre réponse.
la source
Ajoutez une méthode courante 'setText':
Quoi de plus clair que ça? Si vous décidez d'ajouter une autre propriété personnalisable, pas de problème.
la source
setText()
est défini sur la classe Action dont MyAction hérite. Il a probablement déjà un type de retour vide.Tout comme l'a dit Kevin Cline dans sa réponse, je pense que la voie à suivre est de créer une API fluide . Je voudrais simplement ajouter que l'API courante fonctionne mieux lorsque vous avez plusieurs propriétés que vous pouvez utiliser.
Cela rendra votre code plus lisible, et de mon point de vue plus facile et, aham , "sexy" à écrire.
Dans votre cas, cela se passerait comme ça (désolé pour toute faute de frappe, cela fait un an que j'ai écrit mon dernier programme java):
Et l'utilisation serait comme ceci:
la source
Le conseil d'utiliser des constructeurs ou des constructeurs est très bien en général, mais, selon mon expérience, il manque certains points clés pour les actions, qui
Je suggère fortement que le nom, l'info-bulle, l'icône etc ... soit lu à partir d'un fichier de propriétés, XML, etc. Par exemple, pour l'action d'ouverture de fichier, vous pouvez passer une propriété et rechercher
Il s'agit d'un format assez facile à traduire en français, pour essayer une nouvelle meilleure icône, etc. Sans temps de programmation ni recompilation.
Ceci est juste un aperçu, beaucoup est laissé au lecteur ... Cherchez d'autres exemples d'internationalisation.
la source
Il est inutile d'appeler setText (actionText) ou setTooltip ("My tool tool tip") à l'intérieur du constructeur; c'est plus facile (et vous gagnez en performances) si vous initialisez simplement le champ correspondant directement:
Si vous modifiez actionText pendant la durée de vie de l'objet correspondant MyAction, vous devez placer une méthode de définition; sinon, initialisez le champ uniquement dans le constructeur sans fournir de méthode de définition.
Comme l'infobulle et l'image sont des constantes, traitez-les comme des constantes; avoir des champs:
En fait, lors de la conception d'objets communs (pas des beans ou des objets représentant strictement des structures de données), c'est une mauvaise idée de fournir des setters et des getters, car ils cassent en quelque sorte l'encapsulation.
la source
Je pense que cela est vrai si nous allons créer une classe d'actions générique (comme update, qui est utilisée pour mettre à jour Employee, Department ...). Tout dépend du scénario. Si une classe d'action spécifique (comme mettre à jour l'employé) (utilisée à plusieurs endroits dans l'application - Mettre à jour l'employé) est créée avec l'intention de conserver le même texte, info-bulle et image à chaque endroit de l'application (pour un point de vue de cohérence). Le codage en dur peut donc être effectué pour le texte, l'infobulle et l'image pour fournir le texte, l'infobulle et l'image par défaut. Toujours pour donner plus de flexibilité, pour les personnaliser, il devrait avoir des méthodes de définition correspondantes. En gardant à l'esprit seulement 10% des endroits, nous devons le changer. La prise de texte d'action à chaque fois de la part de l'utilisateur peut entraîner un texte différent à chaque fois pour la même action. Comme «Mettre à jour l'Emp», «Mettre à jour l'employé», «Changer d'employé» ou «Modifier l'employé».
la source
Pensez à la façon dont les instances seront utilisées et utilisez une solution qui guidera, voire forcera, les utilisateurs à utiliser ces instances de la bonne manière, ou du moins de la meilleure façon. Un programmeur utilisant cette classe devra s'inquiéter et penser à beaucoup d'autres choses. Cette classe ne doit pas s'ajouter à la liste.
Par exemple, si la classe MyAction est censée être immuable après la construction (et éventuellement une autre initialisation), elle ne devrait pas avoir de méthode de définition. Si la plupart du temps, il utilisera le "Mon texte d'action" par défaut, il devrait y avoir un constructeur sans paramètre, plus un constructeur qui autorise un texte optionnel. Maintenant, l'utilisateur n'a plus besoin de penser à utiliser correctement la classe dans 90% des cas. Si l'utilisateur doit généralement réfléchir au texte, ignorez le constructeur sans paramètre. Maintenant, l'utilisateur est obligé de penser quand cela est nécessaire et ne peut ignorer une étape nécessaire.
Si un
MyAction
instance doit être modifiable après la construction complète, vous avez besoin d'un setter pour le texte. Il est tentant de sauter la définition de la valeur dans le constructeur (principe DRY - "Don't Repeat Yourself") et, si la valeur par défaut est généralement assez bonne, je le ferais. Mais si ce n'est pas le cas, exiger le texte dans le constructeur oblige l'utilisateur à penser quand il le devrait.Notez que ces utilisateurs ne sont pas stupides . Ils ont juste trop de problèmes réels à craindre. En pensant à l '"interface" de votre classe, vous pouvez l'empêcher de devenir un vrai problème aussi - et inutile.
la source
Dans la solution proposée suivante, la superclasse est abstraite et a les trois membres définis sur une valeur par défaut.
La sous-classe a différents constructeurs pour que le programmeur puisse l'instancier.
Si le premier constructeur est utilisé, tous les membres auront les valeurs par défaut.
Si un deuxième constructeur est utilisé, vous donnez une valeur initiale au membre actionText laissant aux deux autres membres la valeur par défaut ...
Si un troisième constructeur est utilisé, vous l'instanciez avec une nouvelle valeur pour actionText et toolTip, en laissant imageURl avec la valeur par défaut ...
Etc.
la source