Scala能否约束对象图,以便只有与上下文相关的对象才可见?

Scala能否约束对象图,以便只有与上下文相关的对象才可见?,scala,abstraction,dci,typeclass,Scala,Abstraction,Dci,Typeclass,有没有一种方法可以使用Scala的类型系统简洁地指定完整对象图的上下文相关子图 DCI认为您通常有一个相当复杂的对象图,但在任何一个用例中,您通常只想使用一个子图。您有一个Foo,它有一个Bar和一个Bat,但是在用例1中,您只关心Bar,在用例2中,只关心Bat 例如,假设您有这个结构,Role1用例需要Foo->Bar->Baz->Bin,Role2用例需要Foo->Bat->Baz->Buz: class Foo{ val bar = new Bar() //Only relevan

有没有一种方法可以使用Scala的类型系统简洁地指定完整对象图的上下文相关子图

DCI认为您通常有一个相当复杂的对象图,但在任何一个用例中,您通常只想使用一个子图。您有一个
Foo
,它有一个
Bar
和一个
Bat
,但是在用例1中,您只关心
Bar
,在用例2中,只关心
Bat

例如,假设您有这个结构,Role1用例需要
Foo->Bar->Baz->Bin
,Role2用例需要
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{}
通过使用traits,很容易看出如何在单个类中限制访问:

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/ 

Scala的类型系统似乎有足够的表现力来做类似的事情,但我无法理解

如果我正确理解了您的问题(我不确定),您希望
Foo
根据
Foo
的类型参数提供
bar
bat
之一

我的第一个机会是:

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()
}
归根结底,我仍然不相信这正是您所要求的,或者说是吗?

在《关于DCI》中,作者介绍了一种在Scala中获得DCI体系结构的方法,这与您的目标类似

基本思想是在trait中定义与您的用例相关的方法,但是它使用自类型注释来确保它是某个基类的对象,而不是您的方法

因此,为了使这一点更容易理解:您有一个数据类
Data
,它包含数据对象的基本组件。当你想实现某个用例,它喜欢在某个角色<代码>角色中考虑<代码>数据< /代码>对象时,你可以准备这样的角色:

trait Role { self : Data => 
  def methodForOnlyThisUseCase = {...}
}
为了执行用例,您可以通过以下方式创建特定于此角色的对象:

val myUseCaseObject = new Data with Role
与此类似,对象
myUseCaseObject
仅限于其
数据
成分以及在给定用例中扮演角色所需的方法


如果它变得更复杂,您可能必须创建类似伪角色特征的东西,它定义了多个用例通用的方法。用例角色的self-type注释将指向这个伪特征,而伪特征self-type注释指向相应的数据类。

不是非常简洁,成员在那里,只是不可能使用,但是朝这个方向走可能是可以接受的

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
}
class Foo[R]{

def bar(implicit ev:R)我认为可以通过类型类实现类似的功能。只需将类型类设置为对象图上的视图,并仅通过类型类访问和操作其内容。我不认为这正是我要寻找的。想想Baz(或者更糟的是,一个包含20个类和交叉引用的图).为了确保Baz.bin仅在Role1中可用,我不是必须为每个角色的每个对象定义一个trait(xExt)并为每个边编写一个转换fn吗?也许这是最好的方法,但我希望找到一种“级联”的方法从Foo到Baz的类型参数很简洁。这有意义吗?所以所有方法都应该包含在原始图中,但是当从某个角色“查看”图时,只有这些方法的子集被公开?我假设通过“子图”您指的是同一组节点,但具有不同的类型相关角色?是的,这正是我所希望的。定义
toRole[T]有意义吗
返回所需类型引用的每个节点的方法?您可能可以使用与上述示例相同的隐式机制。是的,类似于toRole或RoleAdapter是的,这是一篇关于DCI的重要文章,我的问题是从这种类型的设计开始的,但问题是你必须为角色中的每个类显式地编写一个trait。在我的例子中,你最终必须创建一个trait FooInRole1,FooInRole2和BazInRole1,BazInRole2,你甚至必须创建一个BarInRole1才能将角色类型“传递”给Baz。这可能是您所能做到的最好的,但似乎应该有一种方法来避免如此多的命名空间混乱。
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 }
}
trait Role { self : Data => 
  def methodForOnlyThisUseCase = {...}
}
val myUseCaseObject = new Data with Role
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
}