【问题标题】:Pass class as value and create Instance将类作为值传递并创建实例
【发布时间】:2013-01-14 10:44:00
【问题描述】:

我有许多类的共同基本特征。我有一个函数需要创建这些类之一的实例的新实例,但只有在运行时才知道哪一个。

是否可以将此类作为参数传递并在 Scala 中在运行时创建实例?

我什至不确定答案是否是最好的方法,但目前这是我能想到的唯一方法。

【问题讨论】:

    标签: scala


    【解决方案1】:

    你可以这样传递值:

    myFunc(classOf[myObj])
    

    到带有签名的方法

    def myFunc(clazz : AnyRef)={ ...
    

    但这闻起来很糟糕。您正在考虑实现factory pattern,或者更好的是您可以使用多态性并简单地执行以下操作:

    myObj.myFunc
    

    因为您的功能取决于所涉及的类。

    【讨论】:

    • 我想我会使用工厂模式(没有人喜欢臭代码)。
    【解决方案2】:

    与 Java 相同:

    classOf[MyClass].newInstance // calls the constructor without parameters
    classOf[MyClass].getConstructor(/* parameter types */).newInstance(/* parameters */)
    

    Javadoc for Class

    这适用于任何 Scala 版本。 Scala 2.10 有new reflection libraries,它们了解 Scala 概念。

    【讨论】:

      【解决方案3】:

      我建议尽量避免反射,因为它很容易导致难以测试的代码和运行时异常。

      但是,您可以为该类创建一个构建器,如下所示:

      trait Builder[A]{
         def newItem:A
      }
      

      然后将适当的构建器传递给您的函数

      def myFunc[A](param1:B,builder:Builder[A])
      

      你也可以利用隐式

      def myFunc[A](param1:B)(implicit builder:Builder[A])
      

      也许您可以详细说明一下您的用例?

      【讨论】:

        【解决方案4】:

        我个人会避免反思。

        如果您可以预先识别所有可能的用例并使用标识符对其进行分类:

        trait SUPER
        
        class A extends SUPER
        class B extends SUPER
        class C extends SUPER
        class D extends SUPER
        
        val idA = 'CLASS_A
        val idB = 'CLASS_B
        val idC = 'CLASS_C
        val idD = 'CLASS_D
        
        def build(selectedId: Symbol): SUPER = selectedId match {
          case 'CLASS_A => new A
          case 'CLASS_B => new B
          case 'CLASS_C => new C
          case 'CLASS_D => new D
        }
        

        如果您更喜欢建筑商,我会遵循 @Edmondo1984 的建议

        【讨论】:

          【解决方案5】:

          获得所需内容的最“无缝”方式是将执行实例化的方法声明为具有上下文绑定为 ClassManifest 的类型参数

          def maker[T : ClassManifest](args...): T = ...
          

          这将导致编译器自动将ClassManifest[T] 的实例传递给制造商。调用者只需要指定他们想要实例化的特定类。

          package rrs.scribble
          
          import  scala.reflect.ClassManifest
          
          object  Maker
          {
            def maker[T : ClassManifest]: T = {
              val cmT = implicitly[ClassManifest[T]]
              val cT = cmT.runtimeClass
              cT.newInstance.asInstanceOf[T]
            }
          }
          

          这只适用于有问题的类的无参数构造函数。您可以使用参数调用构造函数,但涉及更多。您必须熟悉 Java 反射 API。

          在 REPL 中:

          scala> import rrs.scribble.Maker._
          import rrs.scribble.Maker._
          
          scala> class Argless
          defined class Argless
          
          scala> val s1 = maker[Argless]
          s1: Argless = Argless@1512d075
          

          【讨论】:

          • 我知道,但它们仍然可用并且有替代品,因此该策略有效,并且如图所示可在 2.8 到 2.10 版本之间移植(至少)。
          猜你喜欢
          • 1970-01-01
          • 2022-11-27
          • 2013-12-17
          • 2013-06-23
          • 2015-06-27
          • 1970-01-01
          • 2011-04-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多