2017-01-31 1 views
2

자바에서 데코레이터 패턴을 사용하여 스칼라에서 스태커 블 수정 작업을 수행하고 싶었던 것과 같은 일을 여러 가지 시도해 보았습니다.특성의 추상적 인 가치에 대한 온전한 판단

다음은 필자의 사용 사례입니다. 간단한 자동 완성 기능을 구현하고 있습니다. 그들 중 일부는 트라이의 사용자 지정 구현을 기반으로 구체적인 구현이다

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 
} 

:

/** 
    * 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() 
    } 
} 

:

/** 
    * 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 += _) 
} 

그리고 어떤 다른 스택 수정은 그들은 모두 기본 특성을 구현 그리고 저는 이것을 다음과 같이 사용합니다 :

val autoCompleter = new ParrotAutoCompleter with TolerantAutoCompleter { override val MaxRetries: Int = 5 } 

이 구현은 모두 정상적으로 작동하지만 결함이 있습니다. MaxRetries에서 수행 된 온 전성 검사는 자동 완성기를 사용할 때만 사용하는 경우에만 늦게 완료됩니다. 더 일화적으로, 그것은 한 번이 아닌 매번 실행됩니다.

특성의 메서드 외부에있는 코드는 val 또는 def으로 선언되었는지 여부와 관계없이 MaxRetries이 재정의되기 전에 즉시 실행됩니다.

건설 시간, 재정의 후 및 스택 가능 수정의 속성을 잃지 않고 내 건강 체크를 어떻게 수행 할 수 있습니까?

답변

2

override val MaxRetries = 5 때 익명 클래스의 생성자에서 초기화 된 필드를 만듭니다. 생성자의 흐름은 다음과 같이 간다 : 대신 (A def와)

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

.

+0

귀하의 답변은 정확하지만 귀하가 프레임하는 방식에 대한 설명은 분명하지 않습니다. 나는 당신이이 흐름을 묘사하고있는 코드에 대해 정확히 알지 못한다. (나는 당신이 특성의 온전한 체크를 이동한다는 것을 제외하고는 당신이 나의 발췌 부분에 대해 이야기하고 있다고 상상한다.) 그리고 당신이'anon'을 의미하는 것. . 이 두 가지 점을 명확히 설명해 주시겠습니까? – Dici

+0

재 계산을 피하기 위해'lazy val'을 사용하는 것이 더 표준 적입니다 (그러나 리터럴의 특별한 경우에는'def'가 더 좋을 것입니다). –

+0

@AlexeyRomanov 형질 선언문에서'lazy'를 사용하려고 시도했지만 실제로 컴파일되지는 않았지만 특성의 구체적인 사용법에 사용해야한다고 생각합니다. 문제가 해결 되었습니까 (지금 시도 할 수 없습니까)? 그렇다면이 컨텍스트에서 초기화 순서의 규칙을 설명하는 답변을 추가 할 수 있습니까? – Dici