scala动态确定类型

scala动态确定类型,scala,Scala,我想创建对象实例,其类型由运行时数据决定: trait Business case class Business1() extends Business case class Business2() extends Business object Business { def fromData(data:Array[Byte]): Business = data(0) match { case 1 => new Business1 case 2 => new

我想创建对象实例,其类型由运行时数据决定:

trait Business
case class Business1() extends Business 
case class Business2() extends Business

object Business {
  def fromData(data:Array[Byte]): Business = data(0) match {
    case 1 => new Business1
    case 2 => new Business2
    case _ => throw new RuntimeException("data error")
  }
}
上面的代码可以完成它的工作,但有一个问题,它是关闭的。每当我实现一个新的
业务
子类时,我都必须修改
业务

case 3 => new Business3
如何定义
Business.fromData
一次,然后在不注册的情况下添加
Business3
Business4

编辑


我终于意识到这是一个完美的
多方法的用例,也就是说,基于某个参数的函数进行调度。因此,更一般的问题应该是“如何在scala中实现多重方法”?我相信设计模式的存在仅仅是因为语言能力,这就是为什么我不愿意接受基于工厂的答案。

这并不能解决您的问题,但如果您将
业务
作为一种“密封”特征,那么编译器将在更新
fromData
之前捕获任何非详尽的匹配:

sealed trait Business
case class Business1() extends Business
case class Business2() extends Business

biz match {
    case Business1 => println("Business1")
}
…将导致

warning: match is not exhaustive!
missing combination            Business2

你也可以这样做。虽然我不确定这是否比比赛情况更好。这取决于你想做什么

class Business {
  override def toString = "Business"
}

val factories: Map[Int, () => Business] = Map(
  1 -> (() => new Business {
    override def toString = "Business1"
  }),
  2 -> (() => new Business {
    override def toString = "Business2"
  }),
  3 -> (() => new Business {
    override def toString = "Business3"
  })
)

object Business {
  def fromData(data: Array[Byte]): Business = factories(data(0))()
}

val b = Business.fromData(Array(1,1,2))
println(b)

经典答案是使用注册工厂,即抽象工厂

因此,考虑到上面的层次结构,您可以创建一个“工厂”映射,就像在另一个答案中显示的那样,但您也可以创建对象创建者的平行层次结构,并在启动时注册它们,如下所示:

trait BusinessCreator {
  def createBusiness() : Business 
}
object BusinessCreator1() extends BusinessCreator {
  override def createBusiness() : Business = new Business1()

  factories += "1" -> this
}
//etc.
另一种更具“伸缩性”的方法是跳过并行层次结构,只在工厂对象中注册一个creator函数,从一个伴生对象到每个类,但想法是一样的。

这个呢

val factories = collection.mutable.Map(
  1 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business1"
    }
    override def apply() = single 
  }
  ,2 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business2"
    }
    override def apply() = single 
  }
  ,3 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business3"
    }
    override def apply() = single 
  }
)

我会因为建议java反射而下地狱吗?:)<代码>工厂
仍处于关闭状态这将不起作用,因为“BusinessCreator”实例是延迟创建的-在引用它之前它不会被实例化。因此,您需要引用所有的创建者,这也是一个封闭的过程。