通过Scala中的反射实现/实例化抽象类

时间:2010-02-01 16:30:43

标签: reflection class scala implementation abstract

我正在为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)
    */
}

3 个答案:

答案 0 :(得分: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来设置函数。

答案 1 :(得分:1)

  1. 您无法实例化抽象类
  2. 你不需要抽象类
  3. 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等实例化抽象类...

答案 2 :(得分:0)

如果您真的想以这种方式使用反射(使用运行时代码编译),我认为您最好使用像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从字符串中提供该参数。