2011-09-07 27 views
7

trò chơi của tôi cóloại Class như quan trọng trong bản đồ tại Scala

class Enemy 

ai là AI/chức năng tôi có thể thay đổi với

trait Moving 
trait VerticalMover extends Moving 
trait RandomMover extends Moving 

và vân vân. Bây giờ tôi cần tìm nạp các nội dung đã tải sẵn dựa trên đặc điểm. Những gì tôi muốn làm là có một Bản đồ chấp nhận tất cả các đặc điểm mở rộng Di chuyển dưới dạng khóa và sau đó một số EnemyContainer làm giá trị có nội dung liên quan đến đặc điểm được tải sẵn.

Nhưng làm cách nào để xác định Bản đồ như vậy và định dạng của tôi .get() để nhận vùng chứa bằng một phiên bản của một số Kẻ thù. Một cái gì đó như:

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

Bạn có nghĩa là bạn muốn 'enemyDetailsStore' trả về một điều nếu' myEnemy' mở rộng 'VerticalMover' và một điều khác nếu nó mở rộng' RandomMover'? Điều gì sẽ xảy ra nếu nó mở rộng cả hai? –

+0

Vâng, đó là ý của tôi. Nhưng tôi bắt đầu tự hỏi về sự tỉnh táo của toàn bộ ý tưởng của tôi. Có lẽ tôi nên chỉ có một số chuỗi khóa được nhúng vào trong các đặc điểm và sử dụng nó như là chìa khóa. Vì vậy, với linearization tính trạng các đặc điểm trọng nhất cuối cùng sẽ đặt EnemyContainer nói cách khác là kết cấu được sử dụng để hiển thị kẻ thù. – vertti

+3

Hầu hết thời gian, điểm của một đặc tính/giao diện là để nói "Tôi biết cách làm * X *", trong khi cho phép các triển khai khác nhau của X. Trong trường hợp không có các chi tiết khác, tôi sẽ nghĩ rằng thiết kế tự nhiên nhất sẽ để có đặc điểm 'Di chuyển' có một số loại phương thức' getMovingStrategy' hoặc 'move' trên nó trực tiếp, bạn có thể thực hiện tương ứng theo các phép tính mover thẳng đứng và ngẫu nhiên. –

Trả lời

5

Vâng, tôi giả định rằng cửa hàng chi tiết kẻ thù của bạn là loại Map[Class[_ <: Moving], EnemyDetails]. Tôi nghi ngờ rằng một cái gì đó như:

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

Hoặc:

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

Hoặc thậm chí chỉ:

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

sẽ làm cho bạn. Chỉ có "vấn đề" với mã này là nó là O (N), trong đó nó đòi hỏi một traversal của bản đồ, chứ không phải là một tra cứu đơn giản, mà sẽ là O (1), hoặc O (log N)

10

Có thể bạn có thể bọc Bản đồ [Tệp kê khai, Bất kỳ] đảm bảo rằng các giá trị tương ứng với các phím tệp kê khai.

Bản phác thảo có thể có về điều đó. Lần đầu tiên một chút helper

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]) 
    } 
} 

thì wrapper bản thân (mà không phải là một bản đồ)

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) : _*)) 
} 

Với nó, bạn có thể làm

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

kho: TypedMap = Map (java .lang.String -> foo, Int -> 12, Any -> bar)

Bạn lấy yếu tố với

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

Tôi nghĩ rằng các nhà xây dựng tư nhân nên đảm bảo rằng các _ asInstanceOf là an toàn. inner có thể được công khai, vì nó không thay đổi. Bằng cách này, giao diện phong phú của Map sẽ có sẵn, nhưng rất tiếc, không tạo thêm TypedMap.

Các vấn đề liên quan