2012-01-12 13 views
5

tengo la clase siguiente en mi mente:método de la clase abstracta Scala que devuelve una nueva clase correspondiente objeto secundario

abstract class MyClass (data: MyData) { 

    def update(): MyClass = { 
    new MyClass(process()) 
    } 

    def process(): MyData = { 
    ... 
    } 

} 

Sin embargo, las clases abstractas no pueden ser instanciadas por lo que la línea de new MyClass(process()) es un error. Mi pregunta es: ¿hay alguna forma de decirle al compilador que, en el caso de cada una de las clases secundarias de MyClass, quiero crear un objeto exactamente de esa clase? Parece un exceso de escribir este método en todas las clases de niños. Jugando con los parámetros de tipo de la clase o método no pude lograrlo yo mismo.

+0

(no estoy seguro de si se ajustará a su caso de uso) ¿echó un vistazo a las clases de casos y cómo copiarlos? ... de todos modos si realmente quieres hacer eso, lucharás contra el borrado de tipos. –

Respuesta

6

¿Qué tal algo así? MyClass está parametrizado con el tipo de hormigón. Por supuesto, todas las clases concretas tienen que implementar un método que realmente devuelva una nueva instancia de Self.

trait MyClass[+Self <: MyClass[Self]] { 
    def update(): Self = { 
    makeNew(process()) 
    } 

    def process(): MyData = { 
    // ... 
    } 

    protected def makeNew(data: MyData): Self 
} 

class Concrete0 extends MyClass[Concrete0] { 
    protected def makeNew(data: MyData) = new Concrete0 
} 

class RefinedConcrete0 extends Concrete0 with MyClass[RefinedConcrete0] { 
    override protected def makeNew(data: MyData) = new RefinedConcrete0 
} 

Crédito: IttayD’s second update to his answer a this question.

3

Para evitar por completo la implementación de un método casi idéntico en todas las subclases, necesitaría usar la reflexión. Supongo que ese sería tu último recurso si has elegido a Scala. Así que aquí es cómo minimizar el código repetitivo:

// additional parameter: a factory function 
abstract class MyClass(data: MyData, makeNew: MyData => MyClass) { 

    def update(): MyClass = { 
    makeNew(process()) 
    } 
    def process(): MyData = { 
    ... 
    } 
} 

class Concrete(data: MyData) extends MyClass(data, new Concrete(_)) 

De esta manera se repite sólo el fragmento más corto necesario para crear una instancia de la subclase.

+0

Pero cada instancia de sus objetos ahora tiene un campo adicional, mientras que esto podría definirse como un método abstracto, guardando el campo (para escribir un poco más). –

+0

Cierto, es una compensación, porque no a todo el mundo le gusta escribir "def protegida makeNew (data: MyData) = new Concrete (data)" en cada subclase –

Cuestiones relacionadas