2010-10-31 33 views
6

Me encuentro con un problema estándar como novato en Scala: ¿cómo puedo definir dos clases de tal manera que puedo hacer una instancia de uno que el otro como variable miembro, que a su vez apunta a la primera instancia ?referencias de clases avanzadas en Scala?

me gustaría terminar con una instancia de juego que tiene un miembro de tipo distribuidor que tiene un miembro de tipo de juegos, que es, de hecho, la instancia original Game

Así que en este caso cada instance (Game, Dealer) tiene un miembro que es la otra instancia. ¿Alguien puede guiarme hacia el camino correcto para esto?

Respuesta

2

Creo que está hablando de una dependencia de "dos vías", y esto es fácil de hacer si una de las entidades es inmutable (si quiere que ambas sean inmutables, debería ver la solución de Moviz).

En mi ejemplo dejo que el Game sea la entidad inmutable. Un distribuidor podría no estar involucrado en un juego.

class Dealer(val name: String){ 
    var game: Option[Game] = None 
} 

case class Game(name: String, dealer: Dealer) 

// Instanciate the game and the dealer 
val olle = new Dealer("Olle") 
val ollesGame = Game("Olles Game", olle) 
olle.game = Some(ollesGame) 
+0

Puede usar valores perezosos y fragmentos, como lo muestra Moritz. – Landei

+0

@Landei Gracias. El texto ahora está actualizado. –

3

Usted tiene dos opciones aquí:

  1. Haga sus objetos mutable, a continuación, utilizar exactamente las mismas técnicas que lo haría en Java.
  2. Hazlos inmutables, luego renunciar a las dependencias bidireccionales.

Para ver por qué, considere la siguiente transformación entre árboles (inmutables). Ambos se definen con cada nodo matriz que tenga una lista de nodos secundarios, pero los niños no saben sus padres:

a    (a) 
    b    (b) 
    c    c 
    d  -->  (d) 
    e    e 
    f    f 
    g    g 

En concreto, el nodo d fue clonado con el nuevo valor. Para hacer esto, también tuvimos que clonar todos los nodos principales (que se muestran entre paréntesis).

Si nodos llevaron a cabo su padre, entonces c tendrían que ser "actualizada" para reflejar el nuevo nodo b, y e, f, g tendría que ser actualizado para reflejar el nuevo nodo a. es decir, ¡tendría que copiarse todo el árbol!

Al mantener relaciones solo en una dirección, de padres a hijos, es posible reutilizar c, e, f, g entre versiones sucesivas de la estructura. Esta es una optimización poderosa, y es clave para escribir algoritmos funcionales eficientes.

8

Si realmente necesita para tomar las clases inmutables su única opción es utilizar por los parámetros de nombre en el constructor y siempre crear instancias como perezosos val s:

class Dealer(val name: String, g: => Game) { 
    lazy val game = g 
    override def toString = "Dealer(name=%s, game=%s)".format(name, game.name) 
} 

class Game(val name: String, d: => Dealer) { 
    lazy val dealer = d 
    override def toString = "Game(name=%s, dealer=%s)".format(name, dealer.name) 
} 

lazy val game: Game = new Game("Doppelkopf", new Dealer("Peter", game)) 
lazy val dealer: Dealer = new Dealer("Tina", new Game("Poker", dealer)) 

en cuenta que necesita el tipo de adscripción en el vago vals o no compilará.

+0

@Moriz ¡Whoa! Esas son algunas líneas de programación sofisticadas. Simplemente demuestra que todo es posible en Scala. –

+0

Lo anterior no compila para mí. –

+0

: 5: error: no encontrado: Tipo de juego distribuidor clase (nombre val: String, g: => Juego) { ^ : 5: error: no encontrado: tipo distribuidor clase Juego (nombre val: String , d: => Distribuidor) { ^ –

Cuestiones relacionadas