我尝试了各种各样的事情来做一些非常简单的事情,我会在Java中使用装饰器模式,但想要在Scala中进行可堆叠修改并且失败。
这是我的用例:我实现了一些简单的自动完成程序。它们都实现了一个基本特征:
trait AutoCompleter {
def topSuggestions(prefix: String): Iterator[String]
def update(sentence: String*): Unit
final def topSuggestions(prefix: String, n: Int): List[String] = topSuggestions(prefix).take(n).toList
}
其中一些是基于trie的自定义实现的具体实现:
/**
* This auto-completer learns from the user's input, and therefore does not require a preliminary dictionary.
*/
class ParrotAutoCompleter extends AutoCompleter {
private val trie = new WeightedTrie[Char, String]()
override def topSuggestions(prefix: String): Iterator[String] = trie.prefixedBy(prefix)
override def update(sentence: String*): Unit = sentence.foreach(trie += _)
}
其他一些是可堆叠的修改:
/**
* This auto-completer will try returning some suggestions when the prefix did not match any known word by dropping the
* last character until it finds a suggestion
*/
trait TolerantAutoCompleter extends AutoCompleter {
def MaxRetries: Int
abstract override def topSuggestions(prefix: String): Iterator[String] = {
if (MaxRetries < 1) throw new IllegalArgumentException("Should allow 1 retry minimum, but max retries was: " + MaxRetries)
for (attempt <- 0 to Math.min(prefix.length, MaxRetries)) {
val suggestions = super.topSuggestions(prefix.substring(0, prefix.length - attempt))
if (suggestions.hasNext) return suggestions
}
Iterator()
}
}
我像这样使用它们:
val autoCompleter = new ParrotAutoCompleter with TolerantAutoCompleter { override val MaxRetries: Int = 5 }
这个实现工作正常,但它有一个缺陷:在MaxRetries
上执行的健全性检查是在使用自动完成程序而不是在创建它时才进行的。更有趣的是,它每次运行而不是一次。
问题是,即使在MaxRetries
被覆盖之前,特征中方法外的任何代码都会立即执行(无论是否被声明为val
或{{1} })。
如何在构建时执行完整性检查,在覆盖之后,并且不会失去可堆叠修改的属性?
答案 0 :(得分:2)
当您override val MaxRetries = 5
时,您创建的字段仅在匿名类的构造函数中初始化。构造函数的流程如下:
<jvm>: Initialize MaxRetries field to 0
<anon>: call super
TolerantAutoCompleter: call super
...
TolerantAutoCompleter: sanity check MaxRetries (still 0!)
TolerantAutoCompleter: return
<anon>: set MaxRetries to 5
<anon>: return
使用
new ParrotAutoCompleter with TolerantAutoCompleter { override def MaxRetries = 5 }
(改为def
)。