有时我正在构建一个我希望拥有reset
函数的类。例如
class DFA(val initialState:State) {
var states = Map[State,State]()
var currentState: State = initialState
reset
def reset {currentState = initialState}
}
糟糕!你的干铃没响吗?我将currentState
设置为initialState
两次。进入reset
并进入构造函数一次。我不能让var
未初始化,否则编译器会抱怨。
当然我可以
class DFA(val initialState:State) {
var states = Map[State,State]()
var evilNullVariableWeMustNeverUse = null
var currentState: State = evilNullVariableWeMustNeverUse
reset
def reset {currentState = initialState}
}
但我认为这样做的缺点很明显。
在这个简单的例子中,它并没有那么糟糕,但如果你有5个变量或更复杂的逻辑,它就会变得令人讨厌。
我该如何设计呢?
答案 0 :(得分:3)
也许创建一个Resettable包装器?
class Resettable[T](initial: T) {
var value: T = initial
def reset = value = initial
def :=(other: T) = value = other
}
object Resettable {
implicit def resettable[T](initial: T) = new Resettable(initial)
implicit def fromResettable[T](r: Resettable[T]) = r.value
}
然后:
class DFA(initialState:State) {
var states = Map[State,State]()
var currentState: Resettable[State] = initialState
def changeState(other: State) = currentState := other
def reset = currentState.reset
}
并且:
val dfa = new DFA(new State)
val t: State = dfa.currentState
可以看到以下好处:
class Something {
val a: Resettable[Int] = 0
val b: Resettable[String] = "hi"
}
无需将0
和"hi"
存储在另一个变量中即可重置。
答案 1 :(得分:2)
使其不可变,并使“mutating”方法返回一个新实例。
然后,如果您知道某些时候可能需要返回初始条件,请确保您已按照最初配置保留对该对象的引用。
答案 2 :(得分:1)
class DFA(var initialState:State) {
var states = Map[State,State]()
var currentState: State = _
var reset {currentState = initialState}
reset
}