可堆叠的特征/装饰和抽象类

问题描述 投票:1回答:1

我有一个抽象类(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

目前,decorator的重写方法被忽略(它编译,但不执行)。将abstract修饰符添加到装饰器中的方法不会编译。实施此日志记录解决方案的正确方法是什么?除了可堆叠的特性外,还有其他选择吗?

scala design-patterns
1个回答
4
投票

目前,decorator的重写方法被忽略(它编译,但不执行)

它不会执行,因为它在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 
© www.soinside.com 2019 - 2024. All rights reserved.