在工厂中使用特征

发布于 2024-09-12 11:48:19 字数 311 浏览 9 评论 0原文

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

我尝试了这个:

abstract class Foo {
  ...
}
object Foo {
  def apply() = new Bar

  private class Bar extends Foo {
    ...
  }
}

Foo() with MyTrait // Not working

我想这是因为 with 前面必须有 new

那么有什么办法可以做到这一点吗?

谢谢

I'm currently discovering scala and I was wondering if I could use traits with a factory.

I tried this :

abstract class Foo {
  ...
}
object Foo {
  def apply() = new Bar

  private class Bar extends Foo {
    ...
  }
}

Foo() with MyTrait // Not working

I guess it's because with must be preceded by new.

So is there any way to do this ?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凉宸 2024-09-19 11:48:19

不,已经太晚了,当 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 {
  ...
}

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

No it is too late, the instance is already created when the apply() method returns.

What you can do is using the traits inside the factory method. The code below is from a rather big code example I am writing:

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 {
  ...
}

In this code the type (profession and race) of your Avatar is decided in the factory based on the RaceType and CharacterType enumerations. What you have is one factory for all sorts of different types or type combinations.

情绪操控生活 2024-09-19 11:48:19

假设你有:

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() ,但显然不能。)

Say you have:

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

Then:

Foo() with Baz

would be analogous to:

val foo = new Foo
foo with Baz

which would imply some kind of prototype-based inheritance, which Scala doesn't have. (As far as I know.)

(I'd guess the error in thinking is intuitively mistaking the = sign for a "substitution sign". I.e. since Foo() means Foo.apply() and which "equals" new Foo, you can substitue Foo() with new Foo. Which obviously you can't.)

笙痞 2024-09-19 11:48:19

隐式转换解决方案

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! 

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

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


所以我做了一个新的例子,其中我们“实例中的“monkey patch”实际上使用了该实例:

// --------- 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 方法。

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

Solution with implicit conversion

Ken suggested that a proxy could help us in this case. What we are trying to do here is to add a trait to the instance after it is created. This "monkey patching" could be useful if someone else wrote the class (and the apply() method) and you cannot access the source. In this case you can do is add a proxy/wrapper on top of the instance by implicit conversion (no manual conversion needed):


Using the Foo example we could do this like this:

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!"))

Outputs:

I am really useful, not! 

The reason I do not like this example is:

Baz doesn't use Foo in any way. It is hard to see the reason why we would want to attach the usefulMethod() to Foo.


So I made a new example where the the trait we "monkey patch" into the instance actually uses the instance:

// --------- 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)

Prints:

I am Xerxes, the Elf.

In this example the added Elf trait use the getName method of the instance it extends.

Would be grateful if you see any errors, I am not the good at implicits (yet).

难理解 2024-09-19 11:48:19

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

此示例扩展了 olle 的解决方案,允许用户在调用 apply() 方法时指定 mixin 特征(例如 val xerxes = Avatar [精灵](“薛西斯”))。

// ----- 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)

印刷:

我是精灵薛西斯。

Solution with proxies and implicit conversion

This example extends olle's solution to allow the user to specify the mixin trait when calling the apply() method (e.g. 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)

Prints:

I am Xerxes, the Elf.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文