2012-01-12 12 views
5

Mam następujące klasy w moim umyśle:Scala metoda abstrakcyjna klasa, która zwraca nowy odpowiedniej klasy obiektu podrzędnego

abstract class MyClass (data: MyData) { 

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

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

} 

Jednak klasy abstrakcyjne nie może być instancja więc linia new MyClass(process()) jest błąd. Moje pytanie brzmi - czy istnieje sposób, aby powiedzieć kompilatorowi, że w przypadku każdej z klas potomnych MyClass chcę utworzyć obiekt dokładnie tej klasy potomnej? Wydaje się, że przesadą jest pisanie tej metody we wszystkich klasach dzieci. Grając z parametrami klasy lub metody, nie mogłem tego osiągnąć.

+0

(nie jesteś pewien, czy będzie pasować do twojego przypadku użycia) czy przyjrzałeś się klasom przypadków i jak je skopiować? ... w każdym razie, jeśli naprawdę chcesz to zrobić, będziesz walczyć z wymazaniem typu. –

Odpowiedz

6

Co powiesz na coś takiego? MyClass jest parametryzowany z typem betonu. Oczywiście wszystkie konkretne klasy muszą wdrożyć metodę, która faktycznie zwraca nową instancję z 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 
} 

kredytowe: IttayD’s second update to his answer do this question.

3

Aby całkowicie uniknąć stosowania niemal identycznej metody we wszystkich podklasach, należy użyć refleksji. Sądzę, że to byłaby Twoja ostatnia deska ratunku, gdybyś wybrała Scalę. Więc tutaj jest jak zminimalizować kod powtarzalny:

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

ten sposób można tylko powtórzyć najkrótszy fragment potrzebny do instancji podklasy.

+0

Ale każda instancja twoich obiektów ma teraz dodatkowe pole, podczas gdy można to zdefiniować jako metodę abstrakcyjną, zapisując pole (dla nieco więcej pisania). –

+0

To prawda, jest to jednak kompromis, ponieważ nie wszyscy lubią pisać "protected def makeNew (data: MyData) = new Concrete (data)" w każdej podklasie –

Powiązane problemy