11

不変状態の利点については多くのことが書かれていますが、Scala で可変クラスを優先することが理にかなっている一般的なケースはありますか? (これは、可変クラスを使用した「古典的な」OOP 設計の背景を持つ誰かからの Scala 初心者の質問です。)

3 次元の Point クラスのような些細なことについては、不変性の利点が得られます。しかし、さまざまな制御変数やセンサーの読み取り値を公開する Motor クラスのようなものはどうでしょうか? ベテランの Scala 開発者は、通常、そのようなクラスを不変になるように作成しますか? その場合、「速度」は「var」ではなく「val」として内部的に表され、「setSpeed」メソッドはクラスの新しいインスタンスを返しますか? 同様に、モーターの内部状態を説明するセンサーからの新しい読み取りごとに、Motor の新しいインスタンスがインスタンス化されるでしょうか?

クラスを使用して可変状態をカプセル化する Java または C# で OOP を実行する「古い方法」は、Motor の例に非常によく適合しているようです。したがって、不変状態のパラダイムを使用して経験を積んだら、 Motor のようなクラスを不変になるように設計することさえできるかどうか知りたいです。

4

2 に答える 2

13

別の古典的な OO モデリングの例を使用します: 銀行口座です。

これらは地球上のほぼすべての OO コースで使用されており、通常最終的には次のようなデザインになります。

class Account(var balance: BigDecimal) {
  def transfer(amount: BigDecimal, to: Account): Unit = { 
    balance -= amount
    to.balance += amount
  }
}

IOW: 残高はデータで、転送は操作です。(また、転送は複数の変更可能なオブジェクトを含む複雑な操作であることに注意してください。ただし、複雑ではなく、アトミックである必要があります...したがって、ロックなどが必要です。)

しかし、それは間違っています。それは、銀行システムが実際にどのように設計されているかではありません。実際、現実世界の(物理的な) 銀行業務もそうではありません。実際の物理的な銀行と実際の銀行システムは次のように機能します。

class Account(implicit transactionLog: TransactionLog) {
  def balance = transactionLog.reduceLeft(_ + _)
}

class TransactionSlip(from: Account, to: Account, amount: BigDecimal)

IOW: 残高はオペレーションであり、転送はデータです。ここにあるものはすべて不変であることに注意してください。残高は、トランザクション ログの左側の折り目です。

また、明示的な設計目標として、純粋に機能的で不変の設計には至らなかったことにも注意してください。銀行システムを正しくモデル化したかっただけで、偶然にも純粋に機能的で不変の設計に行き着きました。(実際には偶然ではありません。実際の銀行業務がそのように機能するのには理由があり、プログラミングと同じ利点があります。変更可能な状態と副作用により、システムが複雑でわかりにくくなっています。銀行業務では、つまりお金がなくなる。)

ここでのポイントは、まったく同じ問題を非常に異なる方法でモデル化できるということです。モデルによっては、純粋に不変または非常に難しいものにするのは簡単なことかもしれません。

于 2013-09-30T11:39:32.163 に答える
4

短い答えが最も可能性が高いと思います。はい、不変のデータ構造は、あなたが思っているよりもはるかに使いやすく効率的です。

あなたが提起した質問は、あなたが説明していないソフトウェアシステムよりも、説明したモーターに答えが依存しないため、少しあいまいです。私の意見では、OOP が常に教えられる方法の大きな間違いは、クラスがどのように使用されるかを検討する前に、「ドメイン」クラスのボトムアップ設計を推奨することです。システムでは、モーターに関する同じ情報をさまざまな方法で保持する複数のデータ構造が必要になる場合もあります。

クラスを使用して可変状態をカプセル化するJavaまたはC#でOOPを行う「古い方法」は、モーターの例に非常によく適合しているようです。

マルチスレッドシステムをサポートする「新しい方法」(おそらく)は、可変状態をアクター内にカプセル化することです。モーターの現在の状態を表すアクターは変更可能です。しかし、モーターの状態の「スナップショット」を取り、その情報を別のアクターに渡す場合、メッセージは不変である必要があります。

その [immutable] ケースでは、「speed」は「var」ではなく「val」として内部的に表され、「setSpeed」メソッドはクラスの新しいインスタンスを返しますか?

はい。ただし、ケース クラスを使用する場合は、実際にそのメソッドを記述する必要はありません。として定義されたクラスがあるとしますcase class Motor(speed: Speed, rpm: Int, mass: Mass, color: Color)。メソッドを使用すると、次のcopyように記述できますmotor2 = motor1.copy(rpm = 3500, speed = 88.mph)

于 2013-09-30T03:05:34.190 に答える