Je refactore certains code dans un projet que je travaille et j'ai rencontré une énoncé importante si / sinon si la déclaration suivante suivante:
PanelChooser.getPanel(changer); //Overloaded Method public Panel getPanel(OrangeChanger changer) { Panel orangePanel = new OrangePanel(); return orangePanel; } public Panel getPanel(AppleChanger changer) { Panel applePanel = new ApplePanel(); return applePanel; }
9 Réponses :
Peut-être que vous pouvez faire:
public Panel getPanel(Changer changer) { String changerClassName = changer.class.getName(); String panelClassName = changerClassName.replaceFirst("Changer", "Panel"); Panel panel = (Panel) Class.forName(panelClassName).newInstance(); return panel; }
OK, mais cela nécessite de nommer des conventions pour vos cours; Il doit y avoir un xyzpanel code> pour chaque
xyzchanger code> classe. Et ce n'est pas vraiment en sécurité, car il y a une distribution à
panneau code> là.
IMHO, il vaut mieux éviter de telles manipulations avec des noms de classe, quand ce n'est pas la seule option. Il est plus difficile de maintenir, par exemple. Les modifications de nom de classe ne causeront aucune erreur de compilation.
Oui, ce serait une convention de dénomination. Les conventions sont censées accélérer le développement. Cependant, getpanel code> doit être possible de remplacer, au cas où vous souhaitez modifier la convention pour certains
changeur code>. Ce serait le modèle de conception de l'usine abstraite, au cas où vous vous demandez.
C'est intéressant, je vais rechercher si je peux la mettre en œuvre en Java, merci.
Ce serait déjà Java, sauf si j'ai commis une erreur quelque part :-)
Je ne vois pas assez de code existant et de conception à l'ensemble. Donc, probablement, tout d'abord, j'essaierais de déplacer le code avec l'instanciation du panneau au même endroit où l'instance de changeur est créée. Parce que choisir un panel est la même décision que choisir un changeur. P>
Si un changeur sélectionné est sélectionné de manière dynamique, vous pouvez simplement créer ces panneaux, puis les afficher / les masquer en conséquence. P>
Le changeur est attribué à l'aide d'un appel sur le serveur, le serveur n'a aucun accès au code du panneau, donc malheureusement, ce n'est pas une option.
Je pense que c'est bien que votre première impulsion n'a pas fonctionné :) sinon vous vous coupleriez votre code de changeur (qui devrait être quelque chose à propos de la logique) au code de l'interface utilisateur (panneau) et de mal.
Maintenant, je peux vous offrir La solution suivante: p>
Créer une interface panneauCreator avec un panneau de méthode Createpanel comme ceci: p> maintenant, fournissez 2 implémentations: p> panel = registry.get(changer.getClass()).createPanel();
Une bonne solution rapide, mais cela ne fonctionnera pas si quelqu'un ajoute une sous-classe d'E.G. Orangechanger.
Vous, dans ce cas, le registre doit être mis à jour avec un appel supplémentaire "Met"?
Vous pouvez le faire, mais vous enfreignez le principe de substitution de Liskov. Il n'y a vraiment aucun avantage sur une déclaration IF, en termes de lignes de code dépensées pour atteindre le même résultat.
En théorie, vous avez raison, mais la question ici est de savoir si c'est raisonnable de créer un tel sous-type. Vous avez raison également que la mise en œuvre actuelle n'a aucun avantage, mais l'idée principale était de découpler la logique de la création conditionnelle de panneaux et du changeur. Dans des cas réels, le meilleur design ne sera pas une carte simple mais probablement une configuration plus avancée (probablement XML basée sur le printemps ou autre). Dans ce cas, l'avantage est clair, vous n'avez pas besoin de recompiler votre code une fois que les nouvelles modifications sont créées.
En ce qui concerne les lignes de mesure de code, désolé, je ne l'achète tout simplement pas. Si vous avez besoin de moins de lignes de code, vous pouvez probablement jeter un coup d'œil sur Groovy ou Scala où les fermetures peuvent faire le même travail de manière dynamique, sans avoir besoin de créer une hiérarchie entière de classes comme si j'étais obligé de faire en Java ...
Si vous ajoutez une autre implémentation, vous devez modifier le code / la configuration de cette recherche sur le plan de toute façon, quels que soient, quel que soit son siège ou un registre ou la voie polymorphe. Une sous-classe d'une implémentation existante ne fait pas mal non plus. Il existe certainement un avantage avec l'approche du registre avec le nombre de lignes descendant de manière significative, en plus d'une réduction «apparente» massive de la complexité cyclomatique. Je dis apparent parce que les n-chemins ne descendent pas réellement mais ils sont cachés par la configuration. Quoi qu'il en soit, cela rend le code beaucoup plus simple à lire et à se rapporter à, IMHO.
Le «problème» fondamental ici est que vous avez des hiérarchies de classe parallèle. Vous ne serez pas en mesure de remplacer cette déclaration sans un refactoring assez lourd. Certaines suggestions sont sur C2 Wiki . P>
Le meilleur que vous puissiez faire, et éventuellement une solution parfaitement fine, consiste à déplacer l'instruction IF dans une classe «usine» et à vous assurer qu'elle n'est pas dupliquée nulle part ailleurs. P>
+1 pour l'identification des hiérarchies de classe parallèle. Définitivement un cas pour les usines.
+1 Un motif d'usine est la meilleure solution, il vous offre une certaine flexibilité supplémentaire (par exemple, permettant aux changeurs de changeurs de panneaux), sépare la logique de la classe actuelle et met la "configuration" dans un endroit .
Cela semble être la meilleure idée pour l'instant, je pense que le refactoring au degré nécessaire est au-delà de mon niveau d'expertise et que l'utilisation d'une classe d'usine avec une note sur les possibilités futures satisfera mon niveau actuel.
Au lieu d'usines, je vous recommande vivement d'utiliser Google Guice code.google.com/p/google- Guice
Votre solution ne fonctionnera pas, car Java sélectionne la méthode basée sur le type de compilétime (qui est probablement par exemple pour une instance unique par sous-classe de changeur p> ou si vous avez besoin de nouvelles instances: P> changeur code>). Vous pouvez utiliser une carte
Carte
orangechanger code>.
changerToPanelClass.get(changer.getClass()).newInstance();
Jetez un coup d'œil au usine et abstrait usine motifs. P>
Le modèle fort> usine strong> est un modèle de créationnel tel qu'il est utilisé pour contrôler l'instanciation de classe. Le motif d'usine est utilisé pour remplacer les constructeurs de classe, en suppliant le processus de génération d'objet de sorte que le type de l'objet instancié puisse être déterminé au moment de l'exécution. P>
Abstract Factory strong> Modèle est un modèle de création, car il est utilisé pour contrôler l'instanciation de classe. Le motif d'usine abstrait est utilisé pour fournir à un client un ensemble d'objets liés ou dépendants. La famille d'objets créés par l'usine est déterminée à l'exécution en fonction de la sélection de la classe d'usine concrète. P>
Je ferais ce qui suit: p>
avoir une interface panneauVooser avec une seule méthode renvoyant un panneau pour un changeur. P>
Demandez à une implémentation de CLASSEDPANEDPANELLODOOSER Renvoie un panel lorsque le changement implémente une certaine classe et null autrement. La classe et le panneau à retourner sont passés dans le constructeur. P>
Demandez à une autre implémentation CASCADPANELCHOOSER qui prend une liste de commandes de panneau dans les arguments du constructeur et sur l'appel de sa méthode demande à chaque panneauVooser de fournir un panneau jusqu'à ce qu'il reçoive un panneau NON NULL, puis renvoie ce panneau. P>
N'utilisez pas InstanceOf fort>. Pourquoi le polymorphisme échoue
Le seul endroit à utiliser InstanceOf Strong> est à l'intérieur Equals Strong> Méthode. Pour répondre à votre question. Suivez ce lien .
Crédits à Cowan et Jordao . p>
public abstract class Changer{
private Changer next;
public final boolean handle(Object o) {
boolean handled = doHandle(o);
if (handled) { return true; }
else if (next == null) { return false; }
else { return next.handle(o); }
}
public void setNext(Changer next) { this.next = next; }
protected abstract boolean doHandle(Object o);
}
public class AppleHandler extends Changer{
@Override
protected boolean doHandle(Object o) {
if (!o instanceof Apple ) {
return false;
}
OrangeHandler.handle((Orange) o);
return true;
}
}
S'il y a plus d'une de ces constructions si / else construit dans le code dépendent du type d'instance d'un changeur, vous pouvez utiliser le motif de visiteur comme suit:
panel = PanelChooser.choosePanel(chooser);
Je soupçonne que le second ne fonctionnera pas car vous devrez lancer explicitement le changeur dans une sous-classe pour Java pour identifier la méthode à invoquer. Vous pouvez utiliser une classe / carte de registre (alors des changeurs de carte aux panneaux et recherchez l'instance adoptée) peut-être.
Pourquoi vos noms de classe commencent-ils avec des minuscules?
@U Mad Merci, était une faute de frappe de ma part, fixée