6

我目前正在发现 scala,我想知道是否可以在工厂中使用特征。

我试过这个:

抽象类 Foo {
  ...
}
对象富 {
  def apply() = new Bar

  私有类 Bar 扩展 Foo {
    ...
  }
}

带有 MyTrait 的 Foo() // 不工作

我想这是因为with必须在前面加上new.

那么有没有办法做到这一点?

谢谢

4

4 回答 4

4

不,为时已晚,实例在 apply() 方法返回时已经创建。

您可以做的是使用工厂方法中的特征。下面的代码来自我正在编写的一个相当大的代码示例:

object Avatar {
 // Avatar factory method
 def apply(name: String, race: RaceType.Value, character: CharacterType.Value
  ): Avatar = {
    race match {
      case RaceType.Dwarf => {
        character match {
          case CharacterType.Thief => new Avatar(name) with Dwarf with Thief
          case CharacterType.Warrior => new Avatar(name) with Dwarf with Warrior
          case CharacterType.Wizard => new Avatar(name) with Dwarf with Wizard
        }
      }
      case RaceType.Elf => {
        character match {
          case CharacterType.Thief => new Avatar(name) with Elf with Thief
          case CharacterType.Warrior => new Avatar(name) with Elf with Warrior
          case CharacterType.Wizard => new Avatar(name) with Elf with Wizard
        }
      }
    }
  }
}

class Avatar(val name: String) extends Character {
  ...
}

在此代码中,您的 Avatar 的类型(职业和种族)是在工厂中根据 RaceType 和 CharacterType 枚举决定的。您所拥有的是一个工厂,可用于各种不同类型或类型组合。

于 2010-08-01T10:30:56.660 回答
3

隐式转换的解决方案

Ken 建议在这种情况下代理可以帮助我们。我们在这里尝试做的是在创建实例后为其添加特征。apply()如果其他人编写了类(和方法)并且您无法访问源代码,则此“猴子补丁”可能很有用。在这种情况下,您可以通过隐式转换在实例顶部添加代理/包装器(无需手动转换):


使用Foo示例,我们可以这样做:

class Foo
object Foo { def apply() = new Foo }
trait Baz { def usefulMethod(s: String) = "I am really useful, "+ s }

// ---- Proxy/Wrapper ----
class FooWithBazProxy extends Foo with Baz

// --- Implicit conversion ---
implicit def foo2FooWithBazProxy(foo: Foo): FooWithBazProxy = new FooWithBazProxy

// --- Dummy testcode ---
val foo = Foo()
println(foo.usefulMethod("not!"))

输出:

I am really useful, not! 

我不喜欢这个例子的原因是:

BazFoo以任何方式使用。很难看出我们为什么要附加usefulMethod()Foo.


所以我做了一个新的例子,我们“猴子补丁”到实例中的特征实际上使用了实例:

// --------- Predefined types -----------
trait Race {
  def getName: String
}

class Avatar(val name: String) extends Race{
  override def getName = name
}

object Avatar{ 
  def apply() = new Avatar("Xerxes")
}

// ---------- Your new trait -----------
trait Elf extends Race {
  def whoAmI = "I am "+ getName + ", the Elf. "
}

// ---- Proxy/Wrapper ----
class AvatarElfProxy(override val name: String) extends Avatar(name) with Elf

// ---- Implicit conversion ----
implicit def avatar2AvatarElfProxy(Avatar: Avatar): AvatarElfProxy = new AvatarElfProxy(Avatar.name)


// --- Dummy testcode ---
val xerxes= Avatar()
println(xerxes.whoAmI)

印刷:

I am Xerxes, the Elf.

在此示例中,添加的Elf特征使用getName它扩展的实例的方法。

如果您看到任何错误,将不胜感激,我不擅长隐含(还)。

于 2010-08-03T10:33:51.963 回答
3

假设你有:

class Foo
object Foo { def apply() = new Foo }
trait Baz

然后:

Foo() with Baz

将类似于:

val foo = new Foo
foo with Baz

这意味着某种基于原型的继承,而 Scala 没有。(我所知道的。)

(我猜想思维上的错误是直观地将 = 符号误认为是“替换符号”。即因为 Foo() 表示 Foo.apply() 并且“等于” new Foo,您可以用 new Foo 替换 Foo() . 显然你不能。)

于 2010-08-01T11:19:53.567 回答
2

代理和隐式转换的解决方案

这个例子扩展了 olle 的解决方案,允许用户在调用apply()方法时指定 mixin 特征(例如val xerxes = Avatar[Elf]("Xerxes"))。

// ----- Predefined types -----

trait Race {
   def whoAmI: String
}

class Avatar[R <: Race](val name: String) 

object Avatar {
   def apply[R <: Race](name: String) = new Avatar[R](name)
}

// ----- Generic proxy -----
class AvatarProxy[R <: Race](val avatar: Avatar[R])

implicit def proxy2Avatar[R <: Race](proxy: AvatarProxy[R]): Avatar[R] = 
      proxy.avatar

// ----- A new trait -----
trait Elf extends Race {
   self: AvatarProxy[Elf] =>
   def whoAmI = "I am " + self.name + ", the Elf."
}

implicit def avatar2Elf(avatar: Avatar[Elf]): AvatarProxy[Elf] with Elf = 
      new AvatarProxy[Elf](avatar) with Elf

// --- Test code -----
val xerxes = Avatar[Elf]("Xerxes")
println(xerxes.whoAmI)

印刷:

我是精灵薛西斯。

于 2010-08-03T16:46:00.833 回答