Scala で不変エンティティを効果的に使用して、可変フィールドの恐ろしさと、可変状態から派生するすべてのバグを回避できます。不変エンティティを使用すると、同時実行性が向上し、事態が悪化することはありません。以前の変更可能な状態は、変更のたびに新しい参照を作成する一連の変換になります。
ただし、アプリケーションの特定のレベルでは、変更可能な状態にする必要があります。そうしないと、アプリケーションが役に立たなくなります。アイデアは、プログラムロジックでできる限りそれを押し上げることです。銀行口座の例を見てみましょう。銀行口座は、金利と ATM の引き出しまたは預金のために変更される可能性があります。
2 つの有効なアプローチがあります。
1 つ目は非常にわかりやすいので、1 つ目の詳細を説明します。
case class BankAccount(val balance:Double, val code:Int)
class BankAccountRef(private var bankAccount:BankAccount){
def withdraw(withdrawal) = {
bankAccount = bankAccount.copy(balance = bankAccount.balance - withdrawal)
bankAccount.balance
}
}
これは素晴らしいことですが、まだ同時実行性の管理に行き詰まっています。Scala はそのためのソリューションを提供します。ここでの問題は、BankAccountRef への参照をバックグラウンド ジョブと共有する場合、呼び出しを同期する必要があることです。問題は、最適ではない方法で並行処理を行っていることです。
同時実行の最適な方法: メッセージ パッシング
一方、別のジョブが BankAccount または BankAccountRef でメソッドを直接呼び出すことができず、いくつかの操作を実行する必要があることを通知するだけの場合はどうなるでしょうか? それでは、Scala で並行処理を行うためのお気に入りの方法である Actor があります。
class BankAccountActor(private var bankAccount:BankAccount) extends Actor {
def receive {
case BalanceRequest => sender ! Balance(bankAccount.balance)
case Withdraw(amount) => {
this.bankAccount = bankAccount.copy(balance = bankAccount.balance - amount)
}
case Deposit(amount) => {
this.bankAccount = bankAccount.copy(balance = bankAccount.balance + amount)
}
}
}
このソリューションは、Akka のドキュメント ( http://doc.akka.io/docs/akka/2.1.0/scala/actors.html ) で詳しく説明されています。アクターのメールボックスにメッセージを送信することでアクターと通信し、それらのメッセージは受信順に処理されるという考え方です。したがって、このモデルを使用すると、同時実行性の欠陥が発生することはありません。