2 votes

Trait/décorateur empilable et classe abstraite

J'ai une classe abstraite (bibliothèque Java) qui prend des arguments de constructeur et possède une méthode appelée execute que je souhaite décorer :

public abstract class Task {
    private final String name;

    protected Task(String name) {
        this.name = name;
    }
    public abstract void execute(String str) throws Exception
}

Et j'ai des classes Scala qui héritent actuellement de la précédente :

class FooTask extends Task("fooTask") {
  override def execute(str: String): Unit = println(str + "foo")
}

class BarTask extends Task("barTask") {
  override def execute(str: Strin): Unit = println(str + "bar")
}

Est-il possible d'écrire un décorateur pour une classe Task comme celle-ci :

trait TaskWithErrorLogging { self: Task =>

  override def execute(str: String): Unit =
    Try(self.execute(str)) match {
      case Failure(exception) =>
        println("LOGGED " + exception)
        throw exception;
      case _ =>
    }

}

Et l'utiliser ensuite pour enregistrer les erreurs ?

class BarTask extends Task("barTask") with TaskWithErrorLogging {
  override def execute(str: String): Unit = println(str + "bar") // Error should be logged
}

Ces tâches sont instanciées automatiquement par l'injecteur du framework, il n'y a donc aucun moyen d'écrire new FooTask with TaskWithErrorLogging

Actuellement, la méthode surchargée du décorateur est ignorée (elle se compile, mais ne s'exécute pas). Ajout de abstract à la méthode dans le décorateur ne se compile pas. Quelle est la bonne façon d'implémenter cette solution de journalisation ? Peut-être y a-t-il une autre option que celle d'un trait empilable ?

4voto

Alexey Romanov Points 39124

Actuellement, la méthode surchargée du décorateur est ignorée (elle se compile, mais ne s'exécute pas).

Elle ne s'exécute pas parce qu'elle est remplacée par la fonction BarTask . Et s'il s'exécute, il a une récursivité infinie : self.execute(str) appellera la même méthode.

La méthode la plus simple est la suivante

trait TaskWithErrorLogging extends Task {
  override def execute(str: String): Unit =
    Try(doExecute(str)) match {
      case Failure(exception) =>
        println("LOGGED " + exception)
        throw exception;
      case _ =>
    }

  def doExecute(str: String): Unit
}

class BarTask extends Task("barTask") with TaskWithErrorLogging {
  override def doExecute(str: String): Unit = println(str + "bar")
}

Ou si vous voulez vraiment utiliser des décorateurs empilables, alors TaskWithErrorLogging doit encore être mélangé après la méthode qu'il décore, par exemple

trait TaskWithErrorLogging extends Task { 
  abstract override def execute(str: String): Unit =
    Try(super.execute(str)) match { // note super, not self!
      case Failure(exception) =>
        println("LOGGED " + exception)
        throw exception;
      case _ =>
    }
}

class BarTask0 extends Task("barTask") {
  override def execute(str: String): Unit = println(str + "bar")
}

class BarTask extends BarTask0 with TaskWithErrorLogging

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X