2012-01-12 17 views
5

ho la seguente classe nella mia mente:Scala metodo di classe astratta che restituisce un nuovo oggetto figlio corrispondente classe

abstract class MyClass (data: MyData) { 

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

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

} 

Tuttavia, le classi astratte non possono essere istanziati in modo che la linea di new MyClass(process()) è un errore. La mia domanda è - c'è un modo per dire al compilatore che in caso di ciascuna delle classi figlio di MyClass voglio creare un oggetto esattamente di quella classe figlio? Sembra un eccesso di scrivere questo metodo in tutte le classi di bambini. Giocare con i parametri di tipo della classe o del metodo che non potrei raggiungere io stesso.

+0

(non sono sicuro che si adatti al tuo caso d'uso) hai dato un'occhiata alle case case e come copiarle? ... comunque se vuoi davvero farlo, combatterai contro la cancellazione di tipo. –

risposta

6

Che ne dici di qualcosa del genere? MyClass è parametrizzato con il tipo concreto. Naturalmente, tutte le classi concrete devono implementare un metodo che restituisca effettivamente una nuova istanza di 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 
} 

credito: IttayD’s second update to his answer a this question.

3

Per evitare completamente l'implementazione di un metodo quasi identico in tutte le sottoclassi, è necessario utilizzare la riflessione. Immagino che sarebbe la tua ultima risorsa se hai scelto Scala. : ecco come ridurre al minimo il codice ripetitivo:

// 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(_)) 

In questo modo si ripete solo il frammento più breve necessario creare un'istanza della sottoclasse.

+0

Ma ogni istanza dei tuoi oggetti ora ha un campo in più, mentre questo potrebbe essere definito come un metodo astratto, salvando il campo (per un po 'più di digitazione). –

+0

È vero, è un compromesso, perché, non a tutti piace scrivere "def def come nuovo (dati: MyData) = nuovo Concrete (dati)" in ogni sottoclasse –

Problemi correlati