Je dois gérer deux classes avec des méthodes identiques, mais elles ne mettent pas en œuvre la même interface, elles ne prolongent pas la même superclasse. Je ne peux pas / pas autorisé à changer ces classes et je ne construis pas des instances de ces classes, je n'ai que des objets de cela. Quelle est la meilleure façon d'éviter beaucoup de duplication de code?
Un de la classe: p> et l'autre ... p> (en réalité, ces classes sont plus grandes) p> Ma seule idée est maintenant de créer une classe wrapper dans ceci était la suivante: p> Mais je ne suis pas vraiment satisfait de cette solution. Y a-t-il un moyen meilleur / plus élégant de résoudre ce problème? P> P>
6 Réponses :
Une meilleure solution serait de créer une interface pour représenter l'interface unifiée aux deux classes, puis d'écrire deux classes implémentant l'interface, celle qui enveloppe un A, et une autre qui enveloppe A B:
public interface SomethingWrapper {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
};
public class SomethingAWrapper implements SomethingWrapper {
private SomethingA someA;
public SomethingWrapper(SomethingA someA) {
this.someA = someA;
}
public String getValueOne() {
return this.someA.getValueOne();
}
public void setValueOne(String valueOne) {
this.someA.setValueOne(valueOne);
}
public String getValueTwo() {
return this.someA.getValueTwo();
}
public void setValueTwo(String valueTwo) {
this.someA.setValueTwo(valueTwo);
}
};
Cela ressemble déjà à un gâchis. Pourquoi ne pas arrêter le saignement maintenant?
C'est toujours beaucoup de code identique, oui. Il serait préférable de changer les cours d'origine, mais nous devons prendre le PO à sa parole qu'il ne peut pas. Je conseillerais de passer à une langue typée du canard en premier lieu où ce type de non-sens-le-compilateur-heureux est inouïe de toute façon.
OP peut en réalité avoir la typing de canard en Java avec une réflexion. Peut-être que ce n'est pas une si mauvaise idée.
MH, OK. Cela ne ressemble toujours pas à une solution «belle», mais au moins il vaut mieux s'étendre dans le cas où il y aura des classes identiques.
@NeDbatchelder Je ne suis pas sûr, la solution devient assez laide en raison de toutes les exceptions cochées boiteuses. Si ce n'est vraiment que deux classes, votre approche peut toujours gagner. S'il y a plus de cours, la balance se dirige vers la réflexion.
Si vous n'avez pas le contrôle des deux classes quelque chose code> et quelque chose code> alors vous ne pouvez pas garantir que les futurs ajouts à ces classes auront toujours des signatures correspondantes et si elles n'ont pas Signatures correspondantes alors la version à base de réflexion échouera. Par conséquent, cette solution est préférable car elle est moins fragile aux changements futurs.
là, une solution de canard. Cela acceptera n'importe quel objet avec ValueNeOneOne code>, ValueTwo code> et est trivialement extensible pour d'autres accessoires. public class Wrapper
{
private final Object wrapped;
private final Map<String, Method> methods = new HashMap<String, Method>();
public Wrapper(Object w) {
wrapped = w;
try {
final Class<?> c = w.getClass();
for (String propName : new String[] { "ValueOne", "ValueTwo" }) {
final String getter = "get" + propName, setter = "set" + propName;
methods.put(getter, c.getMethod(getter));
methods.put(setter, c.getMethod(setter, String.class));
}
} catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueOne() {
try { return (String)methods.get("getValueOne").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueOne(String v) {
try { methods.get("setValueOne").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueTwo() {
try { return (String)methods.get("getValueTwo").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueTwo(String v) {
try { methods.get("setValueTwo").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
Merci pour cette approche très générique. Je ne sais pas si ce sera ma solution, car par équipe n'est pas un grand fan de solutions de Refelction. Il y a toujours ces problèmes de performance. On dirait que ceci est simplement un problème laid sans une solution vraiment belle ...
Cela devrait être appelé au moins cent mille fois par seconde (et c'est un seuil très conservateur) pour la performance pour devenir un problème.
Vous pouvez utiliser un proxy dynamique pour créer un "pont" entre une interface que vous définissez et les classes qui sont conformes em> mais ne mettent pas votre interface. Tout commence par une interface: Vous avez maintenant besoin d'un fichier Ensuite, vous pouvez créer votre proxy (mettez-le dans une usine pour une utilisation plus facile): p> InvocationHandler code>, qui transmettra juste des appels à la méthode qui correspond à la méthode d'interface appelée: p> Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl
o.setValueOne("Uno");
System.out.println(o.getValueOne()); // prints: Uno
Je pense que votre classe d'enveloppe d'origine est l'option la plus viable ... Cependant, il peut être fait en utilisant la réflexion, votre vrai problème est que l'application est un désordre ... et la réflexion est pourrait ne pas être la méthode que vous recherchez
J'ai une autre proposition, qui pourrait être de l'aide: créer une classe d'enveloppe qui a des fonctions spécifiques pour chaque type de classes ... elle est surtout copypeaste, mais cela vous oblige à utiliser la chose dactylographiée comme paramètre p>
II a=new XI();
System.out.println("asd"+a.asd());
Vous pouvez probablement exploiter une façade avec la réflexion - à mon avis, il rationalise la façon dont vous accédez à l'héritage et que vous aussi évolutifs!
class facade{
public static getSomething(Object AorB){
Class c = AorB.getClass();
Method m = c.getMethod("getValueOne");
m.invoke(AorB);
}
...
}
J'ai écrit une classe pour encapsuler l'API du cadre de journalisation. Malheureusement, il est trop long de mettre dans cette boîte. P>
Le programme fait partie du projet à http://www.github.com/bradleyross/tatudials < / a> Avec la documentation à http://bradleyross.github.io/tatudials . Le code de la classe bradleyross.library.helpers.exceptionhelper dans les tutoriels de module-commun est à https://github.com/bradleyross/tatudials/blob/master/Tutorials-common/src/main/java/bradleyross/library/HelPers/Exceptionhelper .java . p>
L'idée est que je puisse avoir le code supplémentaire que je souhaite faire les déclarations d'exception plus utiles et je ne vais pas les répéter pour chaque cadre de journalisation. L'emballage n'est pas l'endroit où vous éliminez la duplication de code. L'élimination de la duplication de code est de ne pas avoir à écrire plusieurs versions du code qui appelle l'emballage et les classes sous-jacentes. Voir https://bradleyaross.wordpress.com/2016/05/05 / Java-Logging-Frameworks / P>
La classe bradleyross.helpers.genericPrinter est une autre wrapper qui vous permet d'écrire du code qui fonctionne à la fois avec les classes et les interfaces StrentWriter, et des interfaces Strentwriter. P>