Archivo de la etiqueta: inyeccion

Scala: Cake Pattern

Aunque este blog no sea ni remotamente parecido a las mañanas de Arguiñano, hoy vamos a aprender a cocinar tartas…con Scala para solventar una cuestión de inyección de dependencias (¿cómo?¿lo qué?)

Inyección de dependencias

Supongamos que trabajamos coordinando un equipo de diseño de coches Bercedes Menz. Hay varias áreas de trabajo.
Un grupo se encarga de diseñar el chasis, otro de diseñar las ruedas y otro de diseñar el motor.
¿Cómo especificarías la composición del coche?

Empecemos creando las clases para Coche, Rueda, Chasis y Motor. Y les añadimos un poco de funcionalidad (para que tengan algo de chicha).

class Coche {
  val ruedas : List[_] = ???
  val chasis = ???
  val motor = ???
}
trait Rueda {
  val coeficienteAdherencia: Float
}
trait Chasis {
  val numero_puertas: Int
}
trait Motor {
  val potencia: Int
}

Ahora es cuando, de alguna forma, debemos indicar que Coche depende de todos y cada uno del resto de componentes, pero imaginad que tenemos que usar métodos estáticos para poder implementar las distintas piezas.
¿Qué opciones tenemos? Por una parte podemos parametrizar el coche y agregar esos componentes como miembros de la clase:

class Coche[R<:Rueda,C<:Chasis,M<:Motor]{
  val ruedas: Lista[R] = List()
  val chasis: C = C.newInstance()
  val motor: M = C.newInstance()
}

Mmmm no compila,tío ¿Por qué?

Porque hasta mi abuela se daría cuenta de que esos métodos ‘newInstance’ se encuentan definidos en el companion de las clases C y M. Bueno, se podría decir, pues en vez de parametrizarlo como

R<:Rueda

lo cambiamos por

R<:Rueda.type

Vale, y ahora es cuando te das cuentas de que llevas muchas horas programando a base de café y de que entonces parametrizar esa clase es absurdo, ya que estás haciendo explícitos los parámetros.

¡A cocinar, Carmen de Toledo!

La opción que se propone es la de usar el Cake Pattern, considerada como la respuesta de Scala para el patrón de inyección de dependencias (DI). Este patrón de diseño orientado a objetos, anima a que se le suministren los objetos instanciados en vez de crearlos la propia clase. Si lo aplicamos a nuestro ejemplo, podríamos indicar en la expresión del selftype, que nuestra factoría de coches tiene dependencia de 3 componentes:

trait FactoriaCoches {
  estaFactoriaDependeDe: ComponenteRuedas, ComponenteChasis, ComponenteMotor =>

  case class Coche(val ruedas: List[Rueda], motor: Motor, chasis: Chasis)

  def fabricarCoche = Coche(
    List(new Rueda, new Rueda, new Rueda, new Rueda), //...colina abajo
    Motor("NumeroDeBastidorNoInventadoParaNadaAunqueIgualDeLargo",90),
    Chasis(3))
}

Nótese que se pueden definir miembros y métodos basándose en el hecho de que, en el momento de composición de la factoría, se utilizarán dichos componentes.
Y ahora los componentes se definirían como:

trait ComponenteRueda{
  class Rueda{
    val coeficienteAdherencia: Float = 0.85
  }
  def tiempoFrenada(velocidad: Float, rueda: Rueda): Float = {
    //Aquí van unos cálculos complicados del copón.
    rueda.coeficienteAdherencia * 0.1
    //El resultado es, por ejemplo:
    1
  }
}
trait ComponenteChasis{
  case class Chasis(val numeroPuertas: Int)
}
trait ComponenteMotor{
  case class Motor(val numeroBastidor: String, val potencia: Int)
  def calculaPotencia(numeroBastidor: String): Int= {
    //Un par de llamadas a tráfico y te dicen que la potencia es
    115
  }
}

Es de apreciar el uso de inner classes en los componentes.
Una vez definidos los componentes, ya podemos componer nuestro objeto factoría:

object MiFactoriaDeCoches extends FactoriaCoches 
  with ComponenteRueda 
  with ComponenteChasis
  with ComponenteMotor

val miCocheDeLosDomingos = MiFactoriaDeCoches.fabricarCoche

Si se quisiera añadir otro tipo de rueda o de motor, bastaría con extender al componente en cuestión y luego usarlo en la instanciación del objecto:

trait OtroTipoDeComponenteRueda extends ComponenteRueda{
  //...
}
object OtraFactoriaDeCoches extends FactoriaCoches
  with OtroTipoDeComponenteRueda
  with ComponenteChasis
  with ComponenteMotor

En la próxima entrada veremos tipos estructurales y cómo podemos expresar inyección de dependencias basándonos en dichos tipos.
Y hasta aquí nuestra tarta de hoy.
Rica, rica, … y con fundamento 😉

Deja un comentario

Archivado bajo Tutoriales