2012-01-12 35 views
5

Tôi có lớp sau trong tâm trí tôi:Scala phương pháp lớp trừu tượng mà trả về một lớp tương ứng đối tượng trẻ mới

abstract class MyClass (data: MyData) { 

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

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

} 

Tuy nhiên, lớp trừu tượng không thể được khởi tạo nên dòng new MyClass(process()) là một lỗi. Câu hỏi của tôi là - có cách nào để nói với trình biên dịch rằng trong trường hợp của mỗi lớp con của MyClass tôi muốn tạo ra một đối tượng chính xác mà lớp con? Có vẻ như một overkill để viết phương pháp này awhole trong tất cả các lớp học trẻ em. Chơi với các tham số kiểu của lớp hoặc phương thức tôi không thể đạt được điều đó.

+0

(không chắc chắn nếu nó phù hợp với trường hợp sử dụng của bạn) bạn đã xem qua các trường hợp và cách sao chép chúng? ... dù sao nếu bạn thực sự muốn làm điều đó, bạn sẽ chiến đấu chống lại loại tẩy xoá. –

Trả lời

6

Làm thế nào về một cái gì đó như thế này? MyClass được parametrized với loại bê tông. Tất nhiên, tất cả các lớp cụ thể phải thực hiện một phương thức thực sự trả về một cá thể mới là 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 
} 

Ghi có: IttayD’s second update to his answer đến this question.

3

Để hoàn toàn tránh thực hiện phương pháp gần như giống hệt nhau trong tất cả các lớp con, bạn sẽ cần sử dụng sự phản chiếu. Tôi đoán đó sẽ là phương sách cuối cùng của bạn nếu bạn chọn Scala. Vì vậy, đây là làm thế nào để hạn chế tối đa các mã lặp đi lặp lại:

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

Bằng cách này bạn lặp lại chỉ đoạn ngắn nhất cần thiết để nhanh chóng các lớp con.

+0

Nhưng mọi thể hiện của các đối tượng của bạn bây giờ đều có một trường bổ sung, trong khi điều này có thể được định nghĩa là một phương thức trừu tượng, hãy lưu trường (để gõ nhiều hơn một chút). –

+0

Đúng, đó là một sự cân bằng, bởi vì không phải ai cũng thích viết "bảo vệ def makeNew (dữ liệu: MyData) = new Concrete (dữ liệu)" trong mỗi phân lớp –

Các vấn đề liên quan