2010-06-12 4 views
3

J'ai beaucoup de méthodes pour l'exploitation forestière, comme logSomeAction, logAnotherAction etc.Comment puis-je ajouter des fonctionnalités similaires à un certain nombre de méthodes dans Java?

Maintenant, je veux que toutes ces méthodes font une petite pause après les messages d'impression (Thread.sleep).

Si je le fais manuellement, je ferais quelque chose comme ceci:

//before: 
public static void logSomeAction() { 
    System.out.println (msg(SOME_ACTION)); 
} 

//after: 
public static void logSomeAction() { 
    System.out.println (msg(SOME_ACTION)); 
    try { 
     Thread.sleep (2000); 
    } catch (InterruptedException ignored) { } 
} 

Je me souviens que Java a des classes proxy et d'autres outils magiques prise. Est-il possible d'éviter copier-n-coller N sleep-blocks à N méthodes de journalisation?

Répondre

7

Vous pouvez utiliser Aspects pour ajouter une fonctionnalité "orthogonale" supplémentaire à vos méthodes. Si cela semble trop ésotérique, une solution simple et pratique consisterait à ajouter le sommeil dans une méthode séparée, puis à appeler cette méthode dans chacune de vos méthodes de journalisation. La première fois que vous faites cela, vous devez toucher chaque méthode, mais la prochaine fois si vous voulez modifier le comportement supplémentaire ou ajouter quelque chose d'autre, vous pouvez le faire en un seul endroit.

+1

Tout comme je n'aime pas les aspects, c'est exactement ce qu'ils sont pour. Notez que vous devez utiliser un compilateur distinct, car les aspects ne font pas partie de l'implémentation Java standard; [AspectJ] (http://www.eclipse.org/aspectj/) est commun à Java –

+0

J'aime l'idée des aspects, j'ai même appris quelque chose sur les aspects au printemps. Mais je n'ai pas encore assez de connaissances pour faire cette solution moi-même, mais je dois terminer la tâche. Avez-vous du code approprié ou au moins sscce? quelle dépendance devrait être résolue? – Roman

+0

Les aspects ont l'inconvénient que le code que vous voyez dans votre éditeur n'est pas nécessairement le code en cours d'exécution. –

0

Vous pouvez créer une classe d'utilitaire qui a une méthode SleepFor statique qui inclut votre bloc try ... catch et l'appeler de toutes les méthodes dans lesquelles vous voulez dormir?

2

Il semble que vous souhaitiez utiliser la programmation orientée aspect. Vous pouvez utiliser Spring pour AOP ou AspectJ.

+0

Non, je ne sais pas. Je veux utiliser de vieux proxies simples http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html mais je ne me souviens pas de la syntaxe et je n'ai jamais eu assez d'expérience avec eux. btw, AOP utilise également des proxies sous le capot (peut-être quelques autres implémentations de proxy, mais l'idée est la même). – Roman

+0

Spring AOP oui, mais AspectJ ne le fait pas (il utilise le bytecode-tissage) – Arjan

0

Remplacez tous System.out.println (msg (SOME_ACTION)); avec printAndWait (SOME_ACTION); Vous devriez être en mesure de le faire avec trouver et remplacer. Ensuite, créez une méthode

public static void printAndWait(Object someAction) { 
    System.out.println (msg(someAction)); 
    try { 
     Thread.sleep (2000); 
    } catch (InterruptedException ignored) { 
     Thread.currentThread.interrupt(); 
    } 
} 

De cette façon, le code apparaît une fois et vous pouvez changer facilement en un seul endroit.

0

Remplacez toutes vos méthodes logSomeAction() par une seule méthode logAction(Action a). Ainsi, lorsque vous ajouterez d'autres actions dans le futur, vous ne répéterez pas votre code pour la gestion du journal d'actions et de la mise en veille du thread.

1

L'OP mentionne dans un commentaire que la solution préférée est d'utiliser des proxies java simples. Le code actuel est implémenté en tant que méthodes statiques - pour que les proxys java soient utiles, la classe logger devra être retravaillée en tant qu'interface. Quelque chose comme ceci:

public interface SomeActionLogger 
{ 
    void logSomeAction(); 
    void logSomeOtherAction(); 
    // etc.. 
} 

Vous créez ensuite votre mise en œuvre concrète

public class SystemOutActionLogger implements SomeActionLogger 
{ 
    public void logSomeAction() { 
     System.out.println (msg(SOME_ACTION)); 
    } 
} 

Vous pouvez alors proxies Java envelopper l'interface SomeActionLogger

class DelayAfterInvocationHandler implements InvocationHandler 
{ 
    private Object delegate; 
    private int duration; 

    DelayAfterInvocationHandler(Object delegate, int duration) 
    { 
     this.delegate = delegate; 
     this.duration = duration; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
     Object returnValue = method.invoke(delegate, args); 
     Thread.sleep(duration); 
     // you may want to catch InterruptedEception 
     return returnValue; 
    } 
} 

Pour masquer une partie de la non-soi joli code proxy, vous pouvez alors avoir une méthode qui enveloppe votre enregistreur pour créer le retard, par exemple

public ActionLogger addDelay(SomeActionLogger logger, int delay) 
{ 
    return (ActionLogger)Proxy.newProxyInstance(
     impl.getClass().getClassLoader(), 
     new Class[] { SomeActionLogger.class }, 
     new DelayAfterInvocationHandler(logger, delay)); 
} 

Vous écrivez alors

SomeActionLogger log = addDelay(new SystemOutActionLogger(), 2000); 

Notez que le DelayInvocationHandler est perpendiculaire à l'interface d'enregistrement - il peut être utilisé pour ajouter un délai à toute interface. Vous pourriez alors créer une méthode d'emballage générique comme ceci:

public <T> T addDelay(T delegate, int delay, Class<T> interfaceType) 
{ 
    return (T)Proxy.newProxyInstance(
     delegate.getClass().getClassLoader(), 
     new Class[] { type }, 
     new DelayAfterInvocationHandler(delegate, delay)); 
} 
Questions connexes