我有一个应该生产汽车并与它们一起运行的应用程序。汽车对象创建是一个复杂的过程,因此我需要为每种类型的汽车提供工厂。此外,我希望用户能够提供自己的汽车类型和生产它们的工厂。这些汽车类型和工厂应该作为罐子插入我的应用程序(可能有更好的方式比罐子,但我没有看到它。)
我想到了一个共同的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()方法。可能吗?有没有比我的方法更好的解决方案?
我考虑为工厂制作共同特征,通过反射找到实现特征和触发方法的所有已加载类。但它看起来很复杂。我希望这里可以使用一些设计模式或OOP技巧。你觉得怎么样?
谢谢!
答案 0 :(得分:1)
如果我理解你的问题,你所要做的就是从对象的“身体”中调用注册:
object MercedesFactory extends Factory {
def register() {
CarFactory.knownCarTypes("mercedes") = getClass
}
register
def create() = new Mercedes()
}
答案 1 :(得分:1)
最后我通过反思得到了它。我遍历指定路径上的所有jar,发现所有实现我的 com.example.Factory 特征的类并触发了他们的 register()方法。对于罐子检查,我使用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]
这对我有用。它看起来很棘手,但我希望将来不会破坏我的应用程序中的任何内容。如果有更好的方法,请发帖,我会重新接受答案。