Devuelve el tipo concreto para un rasgo desde su objeto compañero.
Antes, devolvía tipos concretos desde un rasgo, pero nunca desde un objeto compañero de un rasgo y no pude encontrar un ejemplo de mi escenario exacto en línea. Por favor, siéntase libre de indicarme si esto es un duplicado.
Tengo este rasgo:
trait Problem[T <: ProblemInput] {
// utiliza el patrón de plantilla llamando a métodos abstractos implementados en las implementaciones
def solve(problemInput: T): Solution = {
...
}
}
y luego algunas implementaciones de él:
class DoubleCube extends Problem[Cube] {
...
}
class SquareCircle extends Problem[Circle] {
..
}
Quiero poder tener un método de fábrica para mapear una entrada de problema a su problema, es decir:
object Problem {
def apply[T <: ProblemInput](problemInput: T): Problem[T] = input match {
case Cube(_,_) => DoubleCube()
case Circle(_,_) => SquareCircle()
}
}
La solución no se compila con el siguiente error (ejemplo):
type mismatch;
found : DoubleCube
required: Problem[T]
case Cube(_,_) => DoubleCube()
Actualización
Siguiendo el consejo de @Tim: Modifiqué el código para proporcionar una clase de tipo que realizaría la traducción del mapeo, por lo que ahora la implementación se ve así:
trait Translator[T <: ProblemInput] {
def translate(pi: ProblemInput): Problem[T]
}
object TranslatorInstances {
implicit val forCube: Translator[Cube] = (pi: Cube) =>
new DoubleCube()
implicit val forCircle: Translator[Circle] = (pi: Circle) =>
new SquareCircle()
}
object Problem {
def apply[T <: ProblemInput](pi: ProblemInput)(implicit
translator: Translator[T]
): Problem[T] = translator.translate(pi)
...
}
Esto se compila, pero traslada el problema al lado del llamador:
def ladoDelLlamador(pi: ProblemInput): Unit = {
val problem = pi match {
case Cube(_,_) => Problem[Cube]
...
}
problem.solve(pi)
...
}
El compilador se queja de que:
type mismatch;
found : ProblemInput
required: _1
problem.solve(pi)
^
one error found
davy.ai
Devolviendo Tipos Concretos desde Objetos Compañeros de Traits en Scala
El objetivo es tener un método de factoría para mapear una entrada de problema a su problema correspondiente, es decir, crear una instancia de
Problem[T]
basada en unaProblemInput
dada. La implementación inicial devuelve un tipo concreto desde un objeto compañero del trait, pero falla al compilar con un error de tipo incompatible.Una solución es proporcionar una clase de tipo que traduzca el mapeo. Creando un trait
Translator[T]
e instancias implícitas de ella, podemos implementar el objetoProblem
con un métodoapply
que tome unaProblemInput
y unTranslator[T]
como parámetro implícito, y devuelva la correspondiente instancia deProblem[T]
.La solución basada en tipo de clase mantiene la lógica de mapeo centralizada en el objeto
Problem
y ofrece más flexibilidad ya que el traductor puede ser extendido agregando nuevas instancias implícitas de él. Sin embargo, el lado que llama será responsable de pasar elTranslator[T]
correcto al métodoapply
, lo cual puede ser un poco tedioso.En general, devolver tipos concretos desde objetos compañeros de traits puede no ser la mejor opción de diseño, y utilizar una solución basada en tipo de clase puede proporcionar más flexibilidad y una mejor separación de responsabilidades.