2012-06-17 27 views
9

Cho một hệ thống phân cấp lớp như sau:Làm thế nào để trả về thể hiện mới của lớp con trong khi khởi tạo lớp cha?

class A 
    def initialize(param) 
    if param == 1 then 
     #initialize and return instance of B 
    else 
     #initialize and return instance of C 
    end 
    end 
end 

class B < A 
end 

class C < A 
end 

Có thể thực sự khởi tạo và trả về một thể hiện của B hoặc C khi khởi A? I E. my_obj = A.new(param) sẽ dẫn đến my_obj là một phiên bản của lớp B hoặc C tùy thuộc vào giá trị của param, được kiểm tra trong A.initialize(param).

Trong ví dụ của tôi, nó chỉ được biết khi chạy mà lớp con (B hoặc C) để sử dụng và lớp cha (A) về cơ bản chưa bao giờ thực sự được sử dụng. Tôi nghĩ rằng có thể là một ý tưởng tốt để di chuyển logic quyết định liệu B hoặc C vào tổ tiên chung của chúng.

Nếu điều này là không thể (hoặc kiểu xấu), tôi nên đặt séc param và quyết định bắt đầu lớp học ở đâu?

+1

Các câu hỏi tương tự đã được trả lời trước đây.Những gì bạn có thể tìm kiếm là phương pháp nhà máy. Có một cái nhìn tại http://stackoverflow.com/questions/1515577/factory-methods-in-ruby Tôi đoán câu trả lời tại http://stackoverflow.com/a/1515580/1128705 sẽ phù hợp với nhu cầu của bạn. –

Trả lời

8

Bạn đang phá vỡ một nguyên tắc OO cơ bản ở đây - các lớp học nên không biết gì về họ các lớp con. Tất nhiên, đôi khi các nguyên tắc nên bị phá vỡ, nhưng không có lý do rõ ràng để làm điều đó ở đây.

Một giải pháp tốt hơn là chuyển logic lôgic sang phương thức nhà máy trong một lớp riêng biệt. Phương thức factory lấy các đối số giống như đối số khởi tạo của A ở trên, và trả về một cá thể của lớp thích hợp.

+0

Cảm ơn bạn đã nói to. :) Cuối cùng tôi đã viết một phương thức 'initiate_A' trong một mô-đun riêng biệt, quyết định này và trả về một đối tượng mới. –

+0

Có thể có một hoặc hai trường hợp mà điều này là phù hợp mặc dù. Như tôi đã nói trong câu trả lời của tôi, nếu bạn có một lớp phân tích cú pháp, điều đó phải giải quyết, ví dụ, các phiên bản khác nhau của một ngôn ngữ? Bạn có thể có một hàm tạo trả về một cá thể của lớp con bên phải cho phiên bản dữ liệu phù hợp. HTML5 là HTML không phải là một mối quan hệ thừa kế tốt, tôi không biết là gì. – Linuxios

+0

Chúng tôi đồng ý với nhau - nguyên tắc này có thể bị hỏng khi có lý do chính đáng. Không chắc chắn tôi thích ví dụ của bạn mặc dù, nó âm thanh giống như một trường hợp cho Abstract Factory. – ComDubh

3

Vấn đề là giá trị trả lại của initialize bị bỏ qua. đây là những gì sẽ xảy ra khi bạn gọi A.new:

  • new gọi một phương thức lớp học đặc biệt gọi là allocate - điều này trả về một thể hiện rỗng của lớp
  • new sau đó gọi initialize trên đối tượng được trả về bởi allocate, và trả về đối tượng

để làm những gì bạn muốn làm, bạn cần phải ghi đè new và làm cho nó làm những gì bạn muốn:

class A 
    def self.new(args*) 
    if(args[0]==1) 
     B.new(*args[1..-1]) 
    else 
     C.new(*args[1..-1]) 
    end 
    end 
end 

Có điều gì khác cần xem xét. Nếu A là không bao giờ thực sự được sử dụng trên riêng của mình, bạn nên sử dụng một số loại phương pháp nhà máy, hoặc, chỉ là một tuyên bố nếu đơn giản. Ví dụ:

def B_or_C(param,args) 
    (param == 1 ? B : C).new(args) 
end 

Thiết kế thực sự phụ thuộc vào những gì bạn đang sử dụng. Ví dụ: khi bạn có một lớp có thể được sử dụng để xử lý nhiều phiên bản của một thứ gì đó, ví dụ: HTML, bạn có thể có một lớp chính HTMLParser mà vượt quá new và có thể trả về bất kỳ lớp con nào của nó: HTML1Parser, HTML2Parser, HTML3Parser, HTML4ParserHTML5Parser.

Lưu ý: Bạn phải ghi đè lên các phương pháp new để mặc định trong các tiểu lớp để ngăn chặn vòng lặp vô hạn:

def self.new(args*) 
    obj=allocate 
    obj.send(:initialize, *args) 
    obj 
end 
+0

Cảm ơn bạn đã trả lời. Tuy nhiên, khi ghi đè 'self.new' trong' A' và gọi 'A.new (params)', tôi nhận được một lỗi: 'SystemStackError: stack level too deep'. Dường như, việc gọi 'B.new' (hoặc' C.new') bên trong 'A.new' gây ra một vòng lặp vô hạn khi các" hàm tạo "của' B' và 'C' bằng cách nào đó gọi là" hàm tạo "của 'A', cụ thể là 'A.new'. –

+0

Do di sản –

+0

@Torbjoern: Xem Chỉnh sửa. – Linuxios

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