Динамический запуск метода объекта при запуске приложения - PullRequest
1 голос
/ 18 марта 2012

У меня есть приложение, которое должно производить автомобили и работать с ними. Создание объекта автомобиля - сложный процесс, поэтому мне нужен завод для каждого типа автомобиля. Также я хочу, чтобы пользователи могли предоставлять свои собственные автомобили и заводы, которые их производят. Эти типы автомобилей и заводы должны быть подключены к моему приложению в качестве банок (вероятно, есть лучший способ, чем баночки, но я его не вижу).

Я пришел к мысли создать общий CarFactory, который принимает в качестве аргумента название автомобиля ("mercedes", "bmw", "nissan" и т. Д.). У CarFactory есть карта, где каждое имя сопоставлено с собственным классом фабрики. Код выглядит примерно так (извините, я не могу предоставить рабочую копию, потому что я все еще оцениваю ее и у меня нет версии, которая компилируется без ошибок)

import scala.collection.mutable.Map

class CarFactory {
  var knownCarTypes = Map[String, Class[Factory]]()

  def create(carType: String) = knownCarTypes.get(carType) match {
      case Some(factoryClass) => Some(factoryClass.getMethod("create").invoke(null).asInstanceOf[Car])
      case None => None
    }
  }
}

knownCarTypes изменчив, потому что я хочу, чтобы пользовательские фабрики регистрировались на этой карте, указав тип машины, за которую они отвечают, и как называется заводской класс. Так что из пользовательского класса это выглядит так

class Mercedes extends Car

object MercedesFactory extends Factory {
  def register() {
    CarFactory.knownCarTypes("mercedes") = getClass
  }

  def create() = new Mercedes()
}

А вот и мой вопрос. Я не знаю, как вызвать метод register () фабрики пользователей. Является ли это возможным? Есть ли лучшее решение, чем мой подход?

Я думал о том, чтобы создать общую черту для фабрик, найти все загруженные классы, реализующие метод черты и триггера, с помощью отражения. Но это выглядит довольно сложно. Я надеюсь, что здесь можно использовать шаблон дизайна или трюк ООП. Что ты думаешь?

Спасибо!

Ответы [ 2 ]

1 голос
/ 19 марта 2012

Наконец-то у меня все получилось с помощью рефлексии.Я перебрал все jar-файлы по указанному пути, нашел все классы, реализующие мою черту com.example.Factory , и запустил их метод register () .Для проверки банок я использовал Clapper ClassFinder , а для вызова метода объекта я следовал Совету Томаса Юнга. Вот окончательный код

import org.apache.commons.io.FileUtils
import org.clapper.classutil.{ClassFinder, ClassInfo}
import scala.collection.JavaConverters._

def triggerFactories() {
  val jars = FileUtils.iterateFiles(new File("lib"), Array[String]("jar"), true).asScala.toList
  val classes = ClassFinder(jars).getClasses
  val factories = ClassFinder.concreteSubclasses("com.example.Factory", classes)

  factories.foreach { (factory: ClassInfo) =>
    companion[Factory](factory.name).register()
  }
}

def companion[T](name: String)(implicit man: Manifest[T]): T =
  Class.forName(name).getField("MODULE$").get(man.erasure).asInstanceOf[T]

Это сработало для меня.Это выглядит сложно, но я надеюсь, что это не сломает ничего в моем приложении в будущем.Пожалуйста, напишите, если есть лучший подход, я повторно приму ответ.

1 голос
/ 18 марта 2012

Если я правильно понимаю ваш вопрос, все, что вам нужно сделать, это зарегистрироваться в «теле» объекта:

object MercedesFactory extends Factory {
  def register() {
    CarFactory.knownCarTypes("mercedes") = getClass
  }
  register

  def create() = new Mercedes()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...