5

完全なオブジェクト グラフのコンテキスト関連サブグラフを簡潔に指定するために Scala の型システムを使用する方法はありますか?

DCI は、多くの場合、かなり複雑なオブジェクト グラフを使用しているが、どのユース ケースでも、サブグラフのみを操作したい場合が多いと主張しています。と を持つ がFooありBarますBatが、ユースケース 1 の場合は のみを気Barにし、ユースケース 2 の場合はのみを気にしBatます。

たとえば、この構造があり、Role1 ユースケース requiresFoo->Bar->Baz->Binと Role2 ユースケース requiresがあるとしFoo->Bat->Baz->Buzます。

class Foo{
   val bar = new Bar() //Only relevant to Role 1
   val bat = new Bat() //Only relevant to Role 2 
}

class Bar {
   val baz = new Baz() 
}

class Bat {
   val baz = new Baz()
}

//Relevant to both Role 1 and 2 (via Bar or Bat)
class Baz {
  val bin = new Bin() //Only relevant to Role 1
  val buz = new Buz() //Only relevant to Role 2
}

class Bin{}
class Buz{}

特性を使用して、単一のクラスでアクセスを制限する方法を簡単に確認できます。

trait FooInRole1 { def bar : Bar }  //Define accessor in trait
s/Foo/Foo extends FooInRole1/       //Change Foo's declaration to implement trait
val f : FooInRole1 = new Foo        //LHS is i'face, RHS is implementation
//f.bat <--Compile error              Irrelevant field is not available. \o/ 

ただし、ユースケースに関連するすべてのオブジェクトに対してこのパターンを繰り返す必要があります。(たとえば、BazInRole1to accessbinBazInRole2to access が必要ですbiz)

私の質問は、これらの間違いやすい、名前空間が密集している特性をすべて記述することを回避する方法があるかどうかです。たとえば、次のようなコード (コンパイルされない) を想像できます。

class Foo[T] {
  T match { 
    case r1 : Role1 => def bar : Bar[T]
    case r2 : Role2 => def bat : Bat[T]
    case _ => //Nothing
  }
}

val fInRole1 = new Foo[Role1] //Provides Foo->Bar->Baz->Bin
val fInRole2 = new Foo[Role2] //Provides Foo->Bat->Baz->Buz

Scala の型システムはこのようなことを行うのに十分な表現力があるようですが、私にはわかりません。

4

3 に答える 3

1

非常に簡潔ではなく、メンバーがそこにいて、使用することは不可能ですが、この方向に進むことは受け入れられるでしょうか?

class Foo[R] {
  def bar(implicit ev: R <:< Role1) = new Bar[R] //Only relevant to Role 1
  def bat(implicit ev: R <:< Role2) = new Bat[R] //Only relevant to Role 2
}
于 2012-03-12T00:29:17.993 に答える
0

DCI に関するこのartima の記事では、著者は Scala で DCI アーキテクチャを取得する方法を紹介しています。

基本的な考え方は、ユースケースに関連するメソッドを特性で定義することですが、アプローチの代わりに自己型注釈を使用して、特定の基本クラスのオブジェクトであることを確認します。

したがって、これをもう少し親しみやすくするためDataに、データ オブジェクトの基本コンポーネントを含む Data-class があります。Data特定の役割でオブジェクトを検討するのが好きな特定のユースケースを実現したい場合は、Role次のように役割を準備できます。

trait Role { self : Data => 
  def methodForOnlyThisUseCase = {...}
}

ユースケースを実行するには、次の方法でこのロールに固有のオブジェクトを作成します。

val myUseCaseObject = new Data with Role

このように、オブジェクトは、その構成要素と、特定のユースケースでの役割に必要なメソッドmyUseCaseObjectだけに限定されます。Data

より複雑になると、複数のユース ケースに共通するメソッドを定義する疑似ロール トレイトのようなものを作成する必要がある場合があります。ユース ケース ロールの自己型アノテーションは、この疑似特性を指し戻すのに対し、疑似特性の自己型アノテーションは、対応するデータ クラスを指します。

于 2012-02-24T15:38:53.300 に答える
0

私があなたの質問を正しく理解していれば (よくわかりません) 、 の型パラメーターに応じて、またはFooのいずれかを提供してください。barbatFoo

私の最初のショットは次のとおりです。

class Bar
class Bat

trait BarExt { def bar = new Bar }
trait BatExt { def bat = new Bat }

trait Role
case object Role1 extends Role
case object Role2 extends Role

trait RoleProvider[From <: Role, To] {
  def apply(): To
}

object RoleProvider {
  implicit val r1 = new RoleProvider[Role1.type, Foo[Role1.type] with BarExt] {
    def apply() = new Foo[Role1.type] with BarExt
  }

  implicit val r2 = new RoleProvider[Role2.type, Foo[Role2.type] with BatExt] {
    def apply() = new Foo[Role2.type] with BatExt
  }
}

class Foo[T <: Role]

object Foo {
  def create[T <: Role, To](f: T)(implicit rp: RoleProvider[T,To]): To = rp()
}

となることによって

scala> Foo.create(Role1)
res1: Foo[Role1.type] with BarExt = RoleProvider$$anon$3$$anon$1@187b2d93    scala> Foo.create(Role1).bar

scala> Foo.create(Role1).bar
res2: Bar = Bar@7ea4b9da

scala> Foo.create(Role1).bat
<console>:12: error: value bat is not a member of Foo[Role1.type] with BarExt
              Foo.create(Role1).bat

scala> Foo.create(Role2).bat
res3: Bat = Bat@56352b57

scala> Foo.create(Role2).bar
<console>:12: error: value bar is not a member of Foo[Role2.type] with BatExt
              Foo.create(Role2).bar

andの定義に対応する宣言をプルすることでBarExtandを取り除くことができますが、それを扱うのは「難しい」と思います。BatExtr1r2

implicit val r1 = new RoleProvider[Role1.type, Foo[Role1.type] { val bar: Bar }] {
  def apply() = new Foo[Role1.type] { val bar = new Bar }
}

implicit val r2 = new RoleProvider[Role2.type, Foo[Role2.type] { val bat: Bat }] {
  def apply() = new Foo[Role2.type] { val bat = new Bat }
}

要するに、これがまさにあなたが求めていたものであるかどうか、私はまだ確信が持てません。

于 2012-02-23T15:43:29.697 に答える