在scala中实现工厂模式/方法的最佳实践是什么?

时间:2017-11-05 13:42:39

标签: scala

我想知道在scala中实现工厂模式/方法的最佳做法是什么?

说我们有这样的对象:

case class foo1(a:Int,b:String)

case class goo1(z:Double, w:String)

如何以通用的方式创建它们[可能使用特征等...]?

感谢

1 个答案:

答案 0 :(得分:0)

如果您的目标是编写自己的依赖注入模块,即动态提供实例,我强烈建议您查找一些现有工具。对“Scala依赖注入框架”进行简单的Google搜索会产生许多结果,例如MacWireGuiceReaderMonadcake pattern等。

然而,我的判断除了你的动机,并且只是回答这个问题的一种方式,你会在scala中做到这一点也是类型安全的:

trait FactoryMethod[T] {
  type Args
  def defaultArgs: Args
  def withArgs(args: Args): T
  def default: T = withArgs(defaultArgs)
}

case class Foo(a:Int,b:String)
object Foo {
  implicit object factory extends FactoryMethod[Foo] {
    override type Args = (Int,String)

    override def withArgs(args: Args): Foo = (Foo.apply _).tupled(args)

    override def defaultArgs: Args = (1,"foo")
  }
}

case class Goo(z:Double, w:String)
object Goo {
  implicit object factory extends FactoryMethod[Goo] {
    override type Args = (Double,String)

    override def withArgs(args: Args): Goo = (Goo.apply _).tupled(args)

    override def defaultArgs: Args = (2L,"goo")
  }
}

object Factory {
  def of[T](implicit factory: FactoryMethod[T]): factory.Args => T = factory.withArgs
  def instanceOf[T](implicit factory: FactoryMethod[T]): T = factory.default
}

//obtain instance with default arguments
Factory.instanceOf[Goo]

//type safe way of obtaining instance with custom fed arguments
Factory.of[Foo].apply((-22,"baz"))
//By type safe I mean that the line below won't compile because the
//arguments fed for Foo are not compatible:
//Factory.of[Foo].apply(("bar","baz"))

//Note that if you abstract over the types Goo and Foo like this:
//def myMethod[T]: T = {
//  Factory.instanceOf[T]
//}
//It won't compile unless you also ask for the needed implicit
//on the method signature
def myMethod[T: FactoryMethod]: T = {
  Factory.instanceOf[T]
}