不変オブジェクトのみを使用してドメインモデルを構築したいと思います。しかし、valフィールドでトレイトを使用し、いくつかの機能をトレイトに移動したいと思います。次の例を見てください。
trait Versionable {
val version = 0
def incrementVersion = copy(version=version+1)
}
残念ながら、そのようなコードは機能しません-トレイトVersionableのコピー方法は不明です。
すべての特性とクラスに対してコピーメソッドが生成されると便利だと思います。このようなメソッドは、オブジェクトの浅いコピーを作成し、メソッドに渡された引数に従って指定されたフィールドが変更された元のオブジェクトと同じタイプを使用してそれを返す必要があります。
したがって、次の例では:
class Customer(val name: String) extends Versionable {
def changeName(newName: String) = copy(name = newName)
}
val customer = new Customer("Scot")
customer.changeName("McDonnald")
オブジェクトインスタンスを返す必要がありますCustomer(version = 0, name = "McDonnald")
と
customer.incrementVersion
オブジェクトインスタンスも返す必要がありますCustomer(version = 1, name = "Scot")
私の知る限り、Scalaにはそのような機能が現在ないため、クラスコンストラクターをトレイトフィールドで汚染せずに不変のクラスとトレイトを使用することはできません。私の例では、versionという名前のパラメーターをCustomerクラスに導入したくありません。これは、バージョン処理の機能をVersionableトレイトにカプセル化する必要があるためです。
ケースクラスのコピーメソッドの機能と、デフォルトのパラメータを使用してクラスに独自のコピーメソッドを作成する機能は知っていますが、このようなコピーメソッドを特性で使用することはできないため、この機能では問題は解決しないと思います。既存の機能のもう1つの欠点は、copyメソッドを使用する親クラスが、実際にコピーされるオブジェクトのクラスではなく、親クラスを返すことです。
私の質問:
1)上記の例をエレガントな方法で処理する方法を知っていますか。私はScalaを初めて使用するので、すでに良い解決策があるかもしれません。私の意見では、エレガントなソリューションには次の機能が必要です。
リフレクションを使用しないでください
シリアル化を使用しないでください
高速である必要があります
コンパイル時に検証可能である必要があります
2)上記の例のコピーメソッドのコードを生成するコンパイラプラグインを作成することについてどう思いますか?コンパイラプラグインを使用してそれを行うことは可能ですか?それを行うための例やヒントはありますか?