1. ホーム
  2. scala

[解決済み] scalaのミキシンとコンポジション

2023-07-18 14:09:09

質問

javaの世界では(正確には多重継承やミキシンがない場合)、「クラス継承よりもオブジェクト合成を優先する」という非常にシンプルな経験則があります。

特にscalaの場合、mixinも考慮するとどう変わるのか知りたいのですが?

mixinは多重継承の方法として考えられているのでしょうか、それとももっとクラス構成が多いのでしょうか?

また、quot;Favor object composition over class composition" (or the other way around) guidelineがあるのでしょうか?

私は、オブジェクトの構成でも仕事ができるのに、人々がミキシンを使用(または乱用)している非常に多くの例を見てきましたし、どちらが良いのか常にわかりません。これらで非常に似たようなことを達成できるように思えますが、いくつかの違いもあり、いくつかの例もあります。

  • 可視性 - mixin では、すべてが公開 API の一部になりますが、合成の場合はそうではありません。
  • 冗長性 - ほとんどの場合、mixinは冗長性が少なく、少し使いやすいですが、必ずしもそうとは限りません(例:複雑な階層で自己型も使用する場合など)。

短い答えは「It depends"」ですが、おそらく、これかこれが良いという典型的な状況がいくつかあると思います。

私がこれまでに思いついたガイドラインのいくつかの例(私が2つの特性AとBを持っていて、AがBからいくつかのメソッドを使用したいと仮定しています)。

  • BのメソッドでAのAPIを拡張したい場合はミキシンを、そうでない場合はコンポジションを使用します。しかし、作成するクラス/インスタンスがパブリック API の一部でない場合は役に立ちません。
  • ミキシンを必要とするいくつかのパターンを使いたい場合(例えば スタッカブル・トレイト・パターン など) ならば、簡単に決定できます。
  • 循環的な依存関係がある場合、自己型を持つmixinが役に立ちます。(私はこの状況を避けようとしていますが、いつも簡単というわけではありません)
  • もし、動的で、実行時にどのように合成を行うかを決定したいのであれば、オブジェクト合成を使用します。

多くの場合、mixinの方が簡単(および/または冗長でない)ように見えますが、artimaの2つの記事で説明されている"God class"などのように、いくつかの落とし穴があることも間違いないでしょう。 パート 1 , パート2 (ちなみに、他の問題のほとんどは、scalaには関係ない/それほど深刻ではないようです).

このようなヒントは他にもあるのでしょうか?

どのように解決するのですか?

Scalaでは、クラス定義に抽象的な特徴を混ぜるだけにして、オブジェクトのインスタンス化時に対応する具体的な特徴を混ぜれば、mix-inで発生する問題の多くを回避することが可能です。 例えば

trait Locking{
   // abstract locking trait, many possible definitions
   protected def lock(body: =>A):A
}

class MyService{
   this:Locking =>
}

//For this time, we'll use a java.util.concurrent lock
val myService:MyService = new MyService with JDK15Locking 

この構成には、いくつかの利点があります。 第一に、様々な機能の組み合わせが必要となるため、クラスが爆発的に増加するのを防ぐことができます。 第二に、モックオブジェクトのように何もしない具象トレイトを作成し混ぜることができるので、簡単にテストすることができます。 最後に、使用されているロッキングトライトはもちろん、ロッキングが行われていることさえも、サービスの利用者から完全に隠蔽されています。

ミックスインの欠点のほとんどを克服したので、ミックスインとコンポジションの間のトレードオフがまだ残っています。

ミックスインとコンポジションの間のトレードオフが残っています。 私自身は、通常、仮想的なデリゲート オブジェクトが含むオブジェクトによって完全にカプセル化されるかどうか、または潜在的に共有されてそれ自身のライフサイクルを持つことができるかどうかに基づいて決定を下します。 ロックは、完全にカプセル化されたデリゲートの良い例を提供します。 クラスがロックオブジェクトを使用して内部状態への同時アクセスを管理する場合、そのロックは包含オブジェクトによって完全に制御され、そのクラスのパブリックインターフェースの一部として、ロックやその操作が公告されることはありません。このような完全にカプセル化された機能については、私はミックスインを使用します。 データソースのような共有されるものには、コンポジションを使用します。