2012-03-18 8 views
1

私は車を生産して操作するアプリケーションを持っています。車のオブジェクトの作成は複雑なプロセスなので、車の種類ごとに工場が必要です。また、ユーザーが自分のタイプの車とそれを生産する工場を提供できるようにしたい。これらの車のタイプと工場は、私のアプリケーションにjarとしてプラグインされるべきです(おそらくJarよりも良い方法がありますが、私はそれを見ません)。アプリケーション開始時にオブジェクトメソッドを動的にトリガーする

私は、自動車の名前( "メルセデス"、 "BMW"、 "日産"など)を引数として受け入れる共通のCarFactoryを作成する考えに達しました。 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トリックが使えることを願っています。どう思いますか?

ありがとうございます!

+1

を参考にしてください。可変マップを使用する場合は、varとして宣言する必要はありません。 '+ ='はそれをインプレースで変更します。 –

+0

ああ..あなたは正しい。ありがとう:) – Soteric

答えて

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] 

です。それは難しいようですが、将来私のアプリケーションで何かを壊さないことを願っています。より良いアプローチがあれば投稿してください、私は答えを再び受け入れるでしょう。

1

私が正しくあなたの質問を理解していれば、あなたがしなければならないすべては、オブジェクトの「身体」から登録を呼び出すです:

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

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

残念なことに私はMercedesFactoryオブジェクトを(何らかの方法で呼び出すことで)触れるまで、オブジェクト本体を呼び出さないでしょう。 – Soteric

関連する問題