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

时间:2019-04-11 11:24:10

标签: scala design-patterns

我有一个抽象类(Java库),该类带有构造函数参数,并且有一个我要装饰的名为HttpRequest的方法:

execute

我有Scala类,当前继承了前一个:

public abstract class Task {
    private final String name;

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

是否可以为Task类编写这样的装饰器:

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

然后使用它来记录错误?

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修饰符不会编译。什么是实现此日志记录解决方案的正确方法?也许除了可堆叠特征以外还有其他选择吗?

1 个答案:

答案 0 :(得分:3)

  

当前,装饰器的重写方法将被忽略(它会编译,但不会执行)

它没有执行,因为它在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