【问题标题】:Implement/instantiate abstract class via reflection in Scala通过 Scala 中的反射实现/实例化抽象类
【发布时间】:2010-02-01 16:30:43
【问题描述】:

我正在为 Scala 中的 EA(进化算法)项目开发框架。在这一点上,我有一个实现通用 EA 代码的特征,并将诸如基因型转换和适应度测试之类的问题特定代码留给实现此特征的类。但是,由于测试不同的人口选择协议/策略,我不想在实际运行之前完全实现该特征。这给出了代码

trait EAProblem{
// common code ...
   def fitness(ind:Individual):Double
   def selectionStrategy(p: Population): List[(Individual, Double)]
   def nextGeneration(p: Population): Population
}

/* Silly test problem */
abstract class OneMax(logPath: String) extends EAProblem {
  def phenotype(ind:Individual) = {
    ind.genotype
  }
  def fitness(ind: Individual): Double = {
    ind.genotype.size.toFloat / ind.genotype.capacity
  }
}

在运行时选择协议/策略:

object EASelectionStrategyProtocolDemo {
  def main(args: Array[String]) {

    val problem_impl = List[EAProblem](
      // Full replacement
      new OneMax("sigma_strat_full-rep_prot_onemax.log.dat") {
        def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.sigmaScalingMatingSelection(p)
        def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
      },
      new OneMax("boltz_strat_full-rep_prot_onemax.log.dat") {
        def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.boltzmannSelection(p)
        def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
      })
    for(problem <- problem_impl)
       new Simulator(problem)
}

SelectionStrategies/SelectionProtocols 对象包含对 EAProblem 中其他代码的引用的集群。

我现在想要的是使用反射(或其他一些机制)实例化其他抽象类的方法,例如 OneMax(我有很多)。伪代码:

val listOfClassNames = List("OneMax", "classA", "classB", ...)
for(className <- listOfClassNames){
    class_sigma = Class.forname(className)
    /*
    Implement class_class with this code and instantiate it
    def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.sigmaScalingMatingSelection(p)
    def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
    */
    class_boltz = Class.forname(className)
    /*
    Implement class_boltz with this code and instantiate it
    def selectionStrategy(p: Population): List[(Individual, Double)] =
          SelectionStrategies.boltzmannSelection(p)
    def nextGeneration(p: Population): Population = SelectionProtocols.fullReplacement(p)
    */
}

【问题讨论】:

    标签: reflection class scala implementation abstract


    【解决方案1】:

    我不知道你是否可以通过反射来实例化它,同时定义抽象方法。或者,至少,不容易。

    为什么不把这些方法变成函数呢?我的做法是这样的:

    private var _selectionStrategy: Option[Population => List[(Individual, Double)]] = None
    def selectionStrategy(p: Population) = _selectionStrategy.getOrElse(error("Uninitialized selection strategy!"))(p)
    def setSelectionStrategy(f: Population => List[(Individual, Double)]) = if (_selectionStrategy.isEmpty)
      _selectionStrategy = f
    else
      error("Selection strategy already initialized!")
    
    // Same thing for nextGeneration
    

    当然,OneMax 那时就不是抽象的了。实际上,这是重点。然后使用反射创建OneMax 的新实例,这相当简单,并使用setSelectionStrategysetNextGeneration 设置函数。

    【讨论】:

      【解决方案2】:
      1. 你不能实例化抽象类
      2. 你不需要抽象类

      fitness、selectionStrategy、nextGeneration - 都是“独立”变量。因此,将它们捆绑在一个界面中与问题的本质背道而驰。试试这个:

      type Fitness = Individual => Double
      type SelectionStrategy = Population = > List[(Individual, Double)]
      type NextGeneration = Population => Population
      
      case class EAProblem(
        fitness: Fitness, 
        selectionStrategy: SelectionStrategy, 
        nextGeneration: NextGeneration) { /* common code */ }
      
      val fitnesses = List(OneMax, classA, classB, ...)
      val strategies = List(
        SelectionStrategies.sigmaScalingMatingSelection, 
        SelectionStrategies.boltzmannSelection)
      
      fitnesses.map ( fitness => 
        strategies.map ( strategy =>
          EAProblem(fitness, strategy, SelectionProtocols.fullReplacement)))
      

      编辑:你可以用CGLib之类的实例化抽象类……

      【讨论】:

        【解决方案3】:

        如果您真的想以这种方式使用反射(通过运行时代码编译),我认为您最好使用 Python 之类的语言。但我不认为你真的想以这种方式使用反射。

        我认为你最好的选择是让第二类而不是特征包含执行健身测量的例程。例如,

        abstract class Selector {
          def fitness(ind: Individual): Double
          def name: String
        }
        class Throughput extends Selector {
          def fitness(ind: Individual) = ind.fractionCorrect/ind.computeTime
          def name = "Throughput"
        }
        

        然后就可以了

        val selectors = List(new Throughput, new ...)
        val userInputMap = List.map( t => (t.name , t) ).toMap
        

        并按名称查找正确的选择器。

        然后您让 OneMax(和其他人)将选择器作为构造函数参数,您可以通过 userInputMap 从字符串提供。

        【讨论】:

          猜你喜欢
          • 2020-07-10
          • 1970-01-01
          • 1970-01-01
          • 2021-03-23
          • 1970-01-01
          • 1970-01-01
          • 2015-07-22
          • 1970-01-01
          • 2015-06-04
          相关资源
          最近更新 更多