2012-03-18 3 views
1

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

Я пришел к идее сделать обычный 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 изменчив, потому что я хочу пользователя чтобы зарегистрировать на этой карте, какой тип автомобиля они отвечают, и что такое название фабричного класса. Таким образом, из пользовательского класса это выглядит так:

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

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

Спасибо!

+1

как подсказка, если вы используете измененную карту, нет необходимости объявлять ее как var. '+ =' будет изменять его на месте. –

+0

О, ты прав. Спасибо :) – Soteric

ответ

1

Наконец я получил его работы через отражение. Я повторил все баночки по указанному пути, нашел все классы, реализующие мой метод com.example.Factory и вызвал их регистр (). Для осмотра банок я использовал Clapper ClassFinder и для вызова метода объекта я следовал Thomas Jung advice. Вот окончательный код

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

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

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

    def create() = new Mercedes() 
} 
+0

К сожалению, пока я не коснусь объекта MercedesFactory (каким-либо образом, вызывая любой из его методов), он не будет вызывать тело объекта :( – Soteric

Смежные вопросы