Реализовать/создать экземпляр абстрактного класса через отражение в Scala

Я работаю над фреймворком для проекта EA (эволюционный алгоритм) в Scala. В этом у меня есть черта, которая реализует общий код 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)
    */
}

person Community    schedule 01.02.2010    source источник


Ответы (3)


Я не знаю, можете ли вы создать его экземпляр путем отражения, в то же время определяя абстрактные методы. Или, по крайней мере, не легко.

Почему бы вам не превратить эти методы в функции? Я бы поступил примерно так:

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, который достаточно прост, и используете setSelectionStrategy и setNextGeneration для установки функций.

person Daniel C. Sobral    schedule 01.02.2010

  1. вы не можете создать экземпляр абстрактного класса
  2. вам не нужен абстрактный класс

пригодность, 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 или чего-то подобного

person Alexey    schedule 01.02.2010

Если вы действительно хотите использовать отражение (с компиляцией кода во время выполнения) таким образом, я думаю, вам лучше использовать такой язык, как 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.

person Rex Kerr    schedule 01.02.2010