2011-09-07 12 views
7

私のゲームはScalaのマップのキーとしてのクラス型

class Enemy 

人は人工知能/機能私は

trait Moving 
trait VerticalMover extends Moving 
trait RandomMover extends Moving 

などで変更できます。今私は、特性に基づいてプリロードされたものをフェッチする必要があります。私がしたいのは、Movingをキーとして拡張し、EnemyContainerを特性関連のコンテンツをプリロードした値として受け入れるすべての特性を受け入れるマップを持つことです。

しかし、どのように私はそのようなマップを定義し、いくつかの敵のインスタンスによってコンテナを取得するために私の.get()をどのようにフォーマットするのですか?何かが好きです:

val myEnemy = new Enemy with RandomMover 
val myDetails:EnemyContainer = enemyDetailsStore.get(myEnemy.getClass) 
+0

'myEnemy'が' VerticalMover'を拡張する場合は 'enemyDetailsS​​tore'を返し、' RandomMover'を拡張する場合はもう一つのものを返すようにしますか?もしそれが両方に広がったら? –

+0

はい、そうです。しかし私は私の考え全体の健全性を疑問視し始めています。たぶん、私はちょうど形質に埋め込まれたいくつかのキーストリングをキーとして使用するべきです。したがって、特性線形化では、最後のオーバーライド特性はEnemyContainer、つまり敵を表示するために使用されたテクスチャを設定します。 – vertti

+3

ほとんどの場合、特性/インターフェースのポイントは「X *のやり方を知っている」と言いますが、Xの実装方法は違っています。他の詳細がなければ、 'Moving'特性に' getMovingStrategy'や 'move'メソッドを直接持たせることができます。これは、垂直方向とランダムムーバーの下位クラスに適切に実装できます。 –

答えて

5

まあ、私はあなたの敵の詳細ストアはタイプMap[Class[_ <: Moving], EnemyDetails]であることを前提としています。

//gives a Map[Class[_ <: Moving], EnemyDetails] for all matching keys 
enemyDetailsStore.filterKeys(_ isInstance myEnemy) 

または::

//Iterable[EnemyDetails] 
enemyDetailsStore collect { case (c, d) if c isInstance myEnemy => d } 

あるいは単に:

//Option[EnemyDetails] 
enemyDetailsStore collectFirst { case (c, d) if c isInstance myEnemy => d } 

はあなたのために行うのでしょう、私は何かのようなことを疑います。このコードの唯一の「問題」は、簡単な検索ではなく、O(1)またはO(log N)のマップをトラバースする必要があるという点でO(N)です。

10

おそらくMap [Manifest、Any]をラップして値がマニフェストキーに対応していることを確認できます。

可能なスケッチです。 TypedMap =地図(のjava:あなたは

import Typed._ 
val repository = TypedMap("foo", 12, "bar".typedAs[Any]) 

リポジトリを行うことができます最初の小さなヘルパーことで

class Typed[A](value: A)(implicit val key: Manifest[A]) { 
    def toPair: (Manifest[_], Any) = (key, value) 
} 
object Typed { 
    implicit def toTyped[A: Manifest](a: A) = new Typed(a) 
    implicit def toTypable[A](a: A) = new { 
    def typedAs[T >: A : Manifest] = new Typed[T](a)(manifest[T]) 
    } 
} 

、その後(マップではありません)ラッパー自体

class TypedMap private(val inner: Map[Manifest[_], Any]) { 
    def +[A](t: Typed[A]) = new TypedMap(inner + t.toPair) 
    def +[A : Manifest](a: A) = new TypedMap(inner + (manifest[A] -> a)) 
    def -[A : Manifest]() = new TypedMap(inner - manifest[A]) 
    def apply[A : Manifest]: A = inner(manifest[A]).asInstanceOf[A] 
    def get[A : Manifest]: Option[A] = inner.get(manifest[A]).map(_.asInstanceOf[A]) 
    override def toString = inner.toString 
    override def equals(other: Any) = other match { 
    case that: TypedMap => this.inner == that.inner 
    case _ => false 
    } 
    override def hashCode = inner.hashCode 
} 

object TypedMap { 
    val empty = new TypedMap(Map()) 
    def apply(items: Typed[_]*) = new TypedMap(Map(items.map(_.toPair) : _*)) 
} 

.lang.String - > foo、Int - > 12、Any - > bar)

あなたは

repository[String] // returns "foo" 
repository.get[Any] // returns Some("bar") 

を持つ要素を取得し、私はプライベートコンストラクタは_ asInstanceOfが安全であることを確認するべきだと思います。 innerは変更不可能なので公開することができます。このように、Mapの豊富なインターフェイスが利用可能になりますが、残念ながら別のTypedMapを作成しないようにします。

関連する問題