Automatiquement de déléguer toutes les méthodes d'une classe java
Dire que j'ai une classe avec beaucoup de méthodes publiques:
public class MyClass {
public void method1() {}
public void method2() {}
(...)
public void methodN() {}
}
Maintenant, je voudrais créer un wrapper classe qui permettrait de déléguer toutes les méthodes pour enveloppée d'instance (délégué):
public class WrapperClass extends MyClass {
private final MyClass delegate;
public WrapperClass(MyClass delegate) {
this.delagate = delegate;
}
public void method1() { delegate.method1(); }
public void method2() { delegate.method2(); }
(...)
public void methodN() { delegate.methodN(); }
}
Maintenant, si Maclasse a beaucoup de méthodes que j'aurais besoin de remplacer chacun d'eux qui est plus ou moins le même code qui vient de "délégués". Je me demandais si il est possible de faire de la magie pour appeler automatiquement une méthode en Java (donc la classe Wrapper aurait besoin de dire "Hey, si vous appelez une méthode sur moi il suffit d'aller à délégué objet et l'appel de cette méthode).
BTW: je ne peux pas utiliser l'héritage parce que le délégué n'est pas sous mon contrôle.Je viens d'obtenir son instance d'ailleurs (un autre cas serait si MyClass était définitive).
REMARQUE: je ne veux pas IDE génération. Je sais que je peux le faire avec l'aide de l'Ide/Eclipse, mais je suis curieux de savoir si cela peut être fait dans le code.
Des suggestions pour obtenir quelque chose comme cela? (NOTE: je serais probablement capable de le faire dans certains langages de script comme php où je pourrais utiliser php fonctions magiques pour intercepter l'appel).
- Il y a certainement un (simple) de la solution avec de la réflexion, mais voulez-vous accepter les problèmes de performance? La version avec le manuel des délégués est même plus simple à lire.
- J'ai changé tous de retour à la MyClass. Dans ma situation, à la fois classe hérite de MyBaseClass, mais je voulais rendre l'exemple plus simple, donc je l'ai changé hériter de MyClass (j'ai enlevé le modifier avec MyBaseClass, de sorte que vous pouvez pour l'instant l'oublier:).
- Si vous voulez dire que je vais avoir de moins bonnes performances avec la réflexion de ce qui est acceptable. Je préfère ne pas utiliser la réflexion (si possible), mais il est toujours une option acceptable. Si vous n'avez pas idée de comment faire cela avec la réflexion s'il vous plaît poster une réponse. BTW: voir mon commentaire pour une réponse posté par @Nitin Dandriyal
- Je pourrais fournir une solution d'interface commune, c'est à dire
MyClass
etWrapperClass
implémenter la même interface et WrapperClass délégués à cette interface. Ok pour vous? - Oui.. Ce qui semble exactement à ce que je cherche.
Vous devez vous connecter pour publier un commentaire.
Peut-être la dynamique
Proxy
de java peut vous aider. Il ne fonctionne que si vous, par conséquent, l'utilisation des interfaces. Dans ce cas, je vais appeler l'interfaceMyInterface
et mis en place un défaut de mise en œuvre:La classe wrapper mise en œuvre ressemblerait à:
Noter que cette classe:
MyClass
, pour hériter d'un défaut de mise en œuvre (toute autre serait de le faire)Invocationhandler
, afin de permettre au mandataire de la réflexionMyInterface
(pour satisfaire le décorateur modèle)Cette solution vous permet de surcharger des méthodes spéciales, mais de déléguer tous les autres. Cette même travailler avec des sous-classes de la classe Wrapper.
Noter que la méthode
findMethod
n'a pas encore de capturer les cas particuliers.MyInterface
. Tout d'abord vous dire, "Il ne fonctionne que si vous, par conséquent, l'utilisation des interfaces. Dans ce cas, je vais appeler l'interfaceMyInterface
..." mais alors, vous vous dites, "éventuellement mettre en œuvreMyInterface
(pour satisfaire le décorateur des motifs)." Pouvez-vous poster le code pourMyInterface
? Est-il besoin d'avoir de chaque méthode de MyClass? Si oui, qui sorte de vaincre le but de @walkeros de ne pas avoir à manuellement la liste de chaque méthode.MyClass
qui implémente déjàMyInterface
. Le code deMyInterface
peut être dérivée à partir deMyClass
(@Override
méthodes doivent être une partie de l'interface, sinon il ne serait pas compiler). Veuillez noter que cette réponse a été acceptée il y a une année.MyInterface
est facultatif pour lesWrapperClass
, mais obligatoire pourMyClass
, droit? Ce qui, toutefois, est enMyInterface
? Contient-il de chaque méthode deMyClass
? Ce serait super si vous pouviez montrer que dans votre exemple. Aussi,wrapped
etwrapper
ne sont pas de la même classe, non? Je suis en train de faire ce travail avec un décorateur modèle (j'ai un objet que j'aimerais conclure que a des tonnes de méthodes, tout comme @walkeros), mais je suis évidemment manque quelque chose de fondamental ici. Je vous remercie.@Override
. Et honnêtement, Walkeros voulait de cette façon, mais je ne conseille pas d'utiliser cette solution (en utilisant des proxys et de réflexion, juste pour délégué est assez bizarre). Je n'aurais certainement avoir développé une meilleure solution si je l'avais aperçu dans le vrai problème.MyInterface
doit contenir chaque méthode dansMyClass
, comment est-ce mieux que le problème original où chaque méthode est enWrapperClass
? C'est la même quantité de travail/contrat de maintenance avec plus de surcharge. Le vrai problème AFAICT est que lorsque vous utilisez le décorateur motif que vous avez à "délégué" chaque méthode publique de l'objet renvoyé à la ligne (c'est à direpublic void methodN() { delegate.methodN(); }
), qui peut être un énorme tracas. Ce serait bien si le wrapper serait-il suffit d'exécuter toutes les méthodes de remplacement et simplement déléguer tout le reste. Peut-être que je devrais poster une nouvelle question...Cette question est de 6 mois déjà et @CoronA est merveilleux réponse a satisfaits et ont été acceptées par @walkeros, mais j'ai pensé que je voudrais ajouter quelque chose ici que je pense que cela peut être poussé plus loin.
Comme discuté avec @CoronA dans les commentaires de sa réponse, au lieu d'avoir à créer et à maintenir une longue liste de
MyClass
méthodes deWrapperClass
(c'est à direpublic void methodN() { delegate.methodN(); }
), la dynamique de la solution proxy se déplace ce à l'interface. Le problème est que vous avez encore à créer et à maintenir une longue liste de signatures pour l'MyClass
les méthodes de l'interface, qui est peut-être un peu plus simple, mais n'a pas de résoudre complètement le problème. C'est particulièrement le cas si vous n'avez pas accès àMyClass
afin de connaître toutes les méthodes.Selon Trois approches pour la décoration de votre code,
Donc c'est peut-être prévu de limiter le Pattern Décorateur.
@Marc-Bramnik, cependant, donne un fascinant de la solution à l'aide de CGLIB à En interposant sur Java les Méthodes de la Classe (sans interfaces). J'ai été en mesure de combiner cela avec @CoronaA de la solution, afin de créer un wrapper qui peuvent remplacer les méthodes individuelles mais alors passer tout le reste de l'objet enveloppé de sans nécessitant une interface.
Ici est
MyClass
.Ici est
WrapperClass
qui remplace uniquementmethod2()
. Comme vous le verrez ci-dessous, la non-substituée méthodes sont, en fait, pas transmis au délégué, qui peut être un problème.Ici est
MyInterceptor
qui s'étendMyClass
. Il emploie la solution proxy à l'aide de CGLIB comme décrit par @Marc-Bramnik. Il emploie également @CononA de la méthode de détermination de savoir si ou de ne pas envoyer la méthode de l'emballage (si elle est remplacée) ou de l'objet renvoyé à la ligne (si elle ne l'est pas).Ici est
Main
et les résultats que vous obtenez si vous l'exécutez.Comme vous pouvez le voir, lorsque vous exécutez la méthode sur
wrapped
vous obtenez le wrapper pour les méthodes qui ne sont pas remplacées (c'est à diremethod1()
etmethod3()
). Lorsque vous exécutez la méthode surproxified
, cependant, toutes les méthodes sont à exécuter sur l'objet enveloppé sans la douleur d'avoir à déléguer tous dansWrapperClass
ou de mettre toutes les signatures de méthode dans une interface. Grâce à @CoronA et @Marc-Bramnik pour ce qui semble être une super solution à ce problème.SimpleDelegator
classe.) Je ne suis pas un expert en Java, mais je suis relativement confiant que ce est la seule façon. La livraison de la CGLIB bibliothèques ne devrait pas être trop un problème, non? Et si la performance est importante, le Décorateur Modèle est probablement pas la voie à suivre. Pour l'exécuter, j'ai enlevé leSystem.out.println
demethodN()
(donc il ne fait rien) et il a couru 1 million de fois. Peut-être pas un test juste déballé mais il a 0 ms et enveloppé il a fallu 2417 mme.methodN()
1 millions de fois surunwrapped
,wrapped
etproxified
. Toujours pas sûr si c'est juste un test, mais les résultats étaient respectivement de 0 millisecondes, 4 ms et 1485 mme. Il semblerait que le bytecode de la génération de la bibliothèque pourrait avoir une certaine surcharge importante. Mais ça fonctionne!Passer à Groovy 🙂
http://mrhaki.blogspot.com/2009/08/groovy-goodness-delegate-to-simplify.html
@CompileStatic
sur si elle vous fait vous sentir mieux. Considérez-vous la Scala, un langage de script? Peut point être que Java fait de cette lame. Vous êtes en cours d'exécution d'une JVM, d'en tirer parti.Vérifier l' @Délégation annotation de Lombok cadre:
https://projectlombok.org/features/Delegate.html
@Delegate
a été rétrogradé à titre Expérimental, dansv1.14.
projectlombok.org/features/experimental/all stackoverflow.com/a/12807937/378151Vous n'avez pas à faire cela-votre classe Wrapper est une sous-classe de la classe d'origine, afin qu'il hérite de tous publiquement accessible méthodes -- et si vous n'avez pas à les mettre en œuvre, la méthode sera appelée.
Vous ne devriez pas avoir
extends Myclass
avec un privéMyClass
objet -- c'est vraiment vraiment redondant, et je ne peux pas penser à un modèle de conception où en est la droite. VotreWrapperClass
est unMyClass
, et par conséquent, vous pouvez simplement utiliser ses propres champs et des méthodes au lieu de l'appelerdelegate
.EDIT: Dans le cas de
MyClass
êtrefinal
, vous seriez de contourner les willfull déclaration pour ne pas autoriser les sous-classement par "simulation" de l'héritage; je ne peux pas penser à tous ceux qui sont prêts à faire d'autre que vous, qui a le contrôle deWrapperClass
; mais, puisque vous êtes en contrôle deWrapperClass
, pas d'emballage tout ce que vous n'avez pas besoin est vraiment plus qu'une option, c'est la bonne chose à faire, parce que votre objet n'est pas unMyClass
, et ne doit se comporter comme un seul dans le cas, vous mentalement considéré.MODIFIER vous avez changé votre question, signifie quelque chose de complètement différent par la suppression de la
MyClass
super-classe à votreWrapperClass
; c'est un peu dommage, car il annule toutes les réponses apportées jusqu'à présent. Vous devez avoir ouvert une autre question.Définir une méthode dans
WrapperClass
c'est à diredelegate()
qui retourne l'instance deMyClass
OU
Vous pouvez utiliser la réflexion pour le faire, mais l'appelant a passer le nom de la méthode que d'un argument à une méthode exposée. Et il y aura des complications concernant les arguments de la méthode/surcharge des méthodes, etc.
Le code que vous avez posté, a
public class WrapperClass extends MyClass
Fait votre application actuelle de la
WrapperClass
est en fait un décorateur sur le dessus de MyClassLes crédits vont à CoronA pour souligner le Proxy et InvocationHandler classes. J'ai travaillé un plus réutilisable classe utilitaire basé sur sa solution, l'utilisation de génériques:
Tester:
J'ai voulu créer un système automatique de délégation de classe qui exécute le délégataire de méthodes sur l'EDT. Avec cette classe, il vous suffit de créer une nouvelle méthode utilitaire qui va utiliser un EDTDecorator, dans lequel la mise en œuvre se terminera
m.invoke
dans unSwingUtilities.invokeLater
.Cependant, si je réfléchis sur ce, je peut vouloir reconsidérer la non-Réflexion à partir de proxy par l'interface que j'ai - c'est peut-être plus propre et plus rapide, et plus compréhensible. Mais, c'est possible.
Permettez-moi de redéfinir le problème pour un cas spécifique.
Je veux remplacer la méthode close de l'interface ResultSet jdbc. Mon but est de fermer la preparedstatement dans la méthode close de l'ensemble de résultats. Je ne pouvais pas l'accès à la Classe (DelegatingResultSet) qui met en œuvre dans le jeu de résultat de l'interface. Il ya beaucoup de méthodes dans le jeu de résultat de l'interface et de leur remplaçant, un par un, et d'appeler la méthode correspondante de l'objet ResultSet est une solution. Pour une solution dynamique, j'ai utilisé Dynamique ProxyClasses (https://docs.oracle.com/javase/1.5.0/docs/guide/reflection/proxy.html).
//Comment l'appeler: