2016-03-31 58 views
1

這是一個有狀態的類,但據說在scala中類應該是無狀態的,並且狀態對象可能在多線程環境中出現問題。那麼有人可以幫助把它變成一個無國籍班嗎?將有狀態類更改爲無狀態

trait SwitchStrategy { 
    def shouldSwitch: Boolean 
} 

object Strategies { 

    def countdown(counts: Int): SwitchStrategy = { 
    return new SwitchStrategy { 
     private[this] var count = 0 

     override def shouldSwitch: Boolean = { 
     count += 1 
     return if (count >= counts) { 
      count = 0; 
      true 
     } else false 
     } 
    } 
    } 
} 
+0

無國籍對象沒有狀態,你需要一個具有狀態但不能改變的不可變對象。 –

+0

我們是否設法回答您的問題? – slouc

+0

@slouc是的,謝謝 – monk

回答

2

你的整個問題都是基於維護狀態,沒有「神奇的語法」來消除它。方法shouldSwitch不是引用透明:

val s = Strategies.countdown(3) 
println(s.shouldSwitch) // false 
println(s.shouldSwitch) // false 
println(s.shouldSwitch) // true 

如果你要使用的功能模式,同時使用可變狀態勢在必行的解決方案和重寫它不是一個真正的好方法。我不知道你的程序的外部細節,所以我不能幫助改變它。你顯然需要做的第一件事是刪除你的SwitchStrategy依賴的可變狀態。一種常見的解決方案是將呼叫者的狀態信息提供給負責人,在這種情況下,這意味着shouldSwitch的呼叫提供計數。

1

處理狀態的全功能方法稱爲狀態單元。

點擊此處瞭解詳情:http://eed3si9n.com/learning-scalaz/State.html或在這裏:http://timperrett.com/2013/11/25/understanding-state-monad/

有沒有語法或簡單的重構,將讓你從一個樣式更改爲其他。

簡單來說:

實現你預期的結果,而不是修改內部狀態,每一個操作應該返回一對(Result, NewState)和連續作戰,你應該扔掉以前的狀態,並使用新的返回一個。

0

(可變)狀態並不總是不好,有時是不可避免的。迭代器有狀態,I/O流也是這樣......嘗試寫沒有它們的有用的東西。 它也不一定會「在多線程環境中出現問題」......特別是,如果您不在線程之間共享狀態持有者。儘管如此,無狀態(或更確切地說是透明的)代碼更容易推理,並且出於這個原因往往更可靠和更健壯。所以,當你能夠避開「天真」的要求時,通常是一個好主意。

在這種情況下,我想,這樣的事情可能工作:

trait SwitchStrategy { 
     def shouldSwitch: Boolean 
     def next: SwitchStrategy   


     @tailrec 
     final def apply[T](strategy: T => T)(initial: T): T = 
     if(shouldSwitch) initial else next(strategy)(strategy(initial)) 
    } 

    case class CountDown(n: Int) extends SwitchStrategy { 
     def next = n match { 
     case 0 => this 
     case _ => copy(n-1) 
     } 
     def shouldSwitch = n == 0 
    } 

然後,您可以使用它像這樣的例子:

def makeZero = CountDown(10) { n:Int => n - 1 } (10) 
    def plus(a: Int, b: Int) = CountDown(a) { n: Int => n + 1} (b) 
    def pow(a: Int, b: Int) = CountDown(b-1) { n: Long => n * a } (a)