Стекируемый признак / декоратор и абстрактный класс - PullRequest
2 голосов
/ 11 апреля 2019

У меня есть абстрактный класс (библиотека Java), который принимает аргументы конструктора и имеет метод с именем execute, который я хочу украсить:

public abstract class Task {
    private final String name;

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

И у меня есть классы Scala, которые в настоящее время наследуют предыдущий:

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")
}

Можно ли написать декоратор для класса Task следующим образом:

trait TaskWithErrorLogging { self: Task =>

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

}

А затем использовать его для регистрации ошибок?

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

Эти задачи автоматически создаются инжектором фреймворка, поэтому нет возможности записать new FooTask with TaskWithErrorLogging

В настоящее время переопределенный метод декоратора игнорируется (он компилируется, но невыполнение).Добавление модификатора abstract к методу в декораторе не компилируется.Как правильно реализовать это решение для ведения журнала?Может быть, есть и другой вариант, кроме черты стека?

1 Ответ

4 голосов
/ 11 апреля 2019

В настоящее время переопределенный метод декоратора игнорируется (он компилируется, но не выполняется)

Он не выполняется, поскольку он переопределен в BarTask.И если он действительно выполняется, он имеет бесконечную рекурсию: self.execute(str) вызовет один и тот же метод.

Самый простой способ -

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")
}

Или, если вы действительно хотите использовать стекируемые декораторы,тогда TaskWithErrorLogging все еще нужно смешать в после метода, который он украшает, например,

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...