このアプリケーションで、車をモデル化するとします。また、登録済みの車を保管する車のリポジトリをモデル化する必要があります。それをscalaでどのようにモデル化する必要がありますか?
これが私のアプローチです。まず、ケースクラスPlainCar
を作成します。これは、現実の世界に存在する車であり、特別なことは何もありません。次に、CarRepository
を作成します。 RegisteredCar
も作成します。 CarRepository
はPlainCar
sを保存し、それらをRegisteredCar
sとして返すことができるようになりました。 PlainCar
とRegisteredCar
はどちらも、Car
のようなすべてのcomonメソッドを提供する特性drive
を拡張します。ただし、RegisteredCar
は特別です。PlainCar
のインスタンスを所有しますが、登録番号を返すメソッドregistrationNumber
も追加します。他のすべてのメソッドは、PlainCar
インスタンスに委任されるだけです。
しかし、このデザインにはいくつかの欠陥があるように感じます。 1つは、メソッド/プロパティをRegisteredCar
に追加するときに、PlainCar
を変更する必要があることです。これは、実行する必要はないと思います。
したがって、私の質問は、これをより適切にモデル化できるか、もしそうなら、どのようにモデル化できるかということです。私が見逃している他の欠点はありますか?
PlainCar
は私にはかなり厄介に聞こえるので、命名規則に関するいくつかのアドバイスもいただければ幸いです。
登録は、リポジトリのコンテキストでのみ意味を持つ状態であるかのように聞こえます。 2つの状態について説明しました(リポジトリに登録されている、リポジトリに登録されていない)。必要なのは車のコンテナ(お望みならラッパー)のように聞こえます。 Option [Car]または[Car、Motorbike]が1つのオブジェクトしか保持できないのと同じように、1台の車を保持できるコレクションと考えてください。
したがって、RepositoryItem封印された基本特性(または封印された抽象クラス)を作成し、各状態のケースクラスインスタンス(RepositoryItemを拡張する)を作成します。登録済みバリアントには登録番号があります。 RepositoryRepositoryItemsのコンテナを作成します。同じケースクラスのセットの一部であってはなりません。
このアプローチの利点は次のとおりです。
オプションとどちらかの設計方法をご覧ください。少なくともmapを実装して、リポジトリスロットから車を取り出さなくても、車を操作(または自転車に置き換える)できるようにすることをお勧めします。
編集:
あなたのコメントから判断して、混乱を引き起こしたかもしれない点を説明するために...
OptionおよびEitherタイプには、map関数があります(Listおよびその他のモナドと同様)。 map関数を使用すると、含まれているオブジェクトを操作できる関数を渡すことができます。 Optionにラップされたままの変換されたオブジェクトが返されます。
scala> val o = Some(3)
o: Some[Int] = Some(3)
scala> o map (_ * 5)
res2: Option[Int] = Some(15)
OptionとIntの間に依存関係はありませんが、Optionはmapを実装しているため、Intを操作できます。 =削除せずにオプションラッピング。
何かが足りないような気がしますが、あなたのCarRepository
をMap[RegistrationNumber, PlainCar]
または同様のもの。通常、不変オブジェクトを使用すると、元のオブジェクトの外部でこの種の関連付けを作成する方がはるかに簡単です。
私の2番目の選択肢はRegisteredCar extends PlainCar
ですが、これにより不要な結合とコピーが作成されると思います。これらのオプションはどちらも、PlainCar
の名前をCar
に変更するだけです。