16

関数型プログラミングは、不変クラスと参照透過性を促進します。

ドメイン駆動設計は、値オブジェクト (不変) とエンティティ (可変) で構成されます。

可変エンティティではなく、不変エンティティを作成する必要がありますか?

プロジェクトがメイン言語として Scala を使用していると仮定してみましょう。同時実行性を扱っている場合、古い状態を危険にさらすことなく、エンティティをケース クラス(不変なので) として記述するにはどうすればよいでしょうか?

良い習慣とは何ですか?エンティティを変更可能 (varフィールドなど) に保ち、ケース クラスの優れた構文を回避しますか?

4

2 に答える 2

15

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 ) で詳しく説明されています。アクターのメールボックスにメッセージを送信することでアクターと通信し、それらのメッセージは受信順に処理されるという考え方です。したがって、このモデルを使用すると、同時実行性の欠陥が発生することはありません。

于 2013-02-11T14:33:25.600 に答える
10

これは、あなたが思っているほどスカラ固有ではない意見の質問のようなものです。

FP を本当に採用したい場合は、すべてのドメイン オブジェクトに対して不変のルートを使用し、それらに動作を加えることはありません。

これは、動作と状態が常に分離されているサービス パターンと呼ぶ人もいます。これは OOP では避けられましたが、FP では自然でした。

また、ドメインが何であるかにもよります。UI やビデオ ゲームなどのステートフルなものを使用すると、OOP の方が簡単になる場合があります。Web サイトや REST などのハードコアなバックエンド サービスについては、サービス パターンの方が優れていると思います。

頻繁に言及される並行性以外に、不変オブジェクトについて私が気に入っている 2 つの非常に優れた点は、キャッシュの信頼性がはるかに高いことと、意図が非常に明確であるため、分散メッセージ パッシング (例: amqp を介した protobuf) にも適していることです。

また、FP の人々は、可変から不変への架け橋と戦うために、DSL (ビルダー、モナド、パイプ、矢印、STMなど) とも呼ばれる「言語」または「対話」を作成して、変異させてから不変に戻すことができます。ドメイン。上記のサービスは、DSL を使用して変更を加えます。これは、あなたが思っているよりも自然なことです (たとえば、SQL は「対話」の例です)。一方、OOP は変更可能なドメインを持ち、言語の既存の手続き部分を活用することを好みます。

于 2013-02-11T14:29:28.063 に答える