2011-02-04 38 views

Trả lời

25

Ruby không có lớp lồng nhau.

Cách duy nhất để kế thừa hành vi là, tốt, thông qua kế thừa.

Nếu bạn muốn mã của mình hoạt động, bạn cần sử dụng ngôn ngữ hỗ trợ các lớp lồng nhau. Trong khi đây là một tính năng gọn gàng và mạnh mẽ vô cùng, tôi không may biết chỉ có hai ngôn ngữ mà đã lồng các lớp:

  • BETA, ngôn ngữ mà giới thiệu các lớp lồng nhau (và người kế nhiệm của nó gbeta)
  • Newspeak

Tôi không biết điều gì khác.

Java có cấu trúc được gọi là các lớp lồng nhau, nhưng chúng có một số hạn chế thiết kế không may.

Trong ví dụ của bạn ở trên, nó không phải là lớp B được lồng vào bên trong A, nó là liên tụcB được lồng vào bên trong A. Hãy nghĩ về điều này:

C = A::B 

Bây giờ, lớp được phát hành theo hai tên: A::BC. Phải rõ ràng là C là toàn cầu và không được lồng vào bên trong A. (Vâng, thực ra, C được lồng bên trong Object, bởi vì không có hằng số thực sự toàn cầu, nhưng đó là bên cạnh điểm.) Nhưng vì CA::B là cùng một lớp, rõ ràng là không thể lồng nhau và không lồng nhau. Kết luận hợp lý duy nhất là lớp chính nó không được lồng nhau.

Tính năng xác định của các lớp lồng nhau là tra cứu phương pháp đi dọc theo hai chiều: nâng chuỗi thừa kế và ra ngoài qua lồng. Ruby, giống như 99,9% của tất cả các ngôn ngữ OO, chỉ hỗ trợ các ngôn ngữ cũ. (Trong một số nghĩa nào đó, các lớp lồng nhau không chỉ thừa hưởng các đặc tính của lớp cha của chúng, mà còn là các tính năng của lớp xung quanh của chúng.)

+0

Cảm ơn bạn đã thêm nhận xét làm rõ, +1 từ tôi. –

+2

@Michael Kohl: Đó không phải là các lớp lồng nhau, đó là các hằng số không gian tên. Câu đầu tiên làm đúng. Những gì tôi cho rằng đã xảy ra là câu thứ hai ban đầu đọc một cái gì đó như "hằng lồng nhau đề cập đến các lớp", và họ nghĩ rằng nó có vẻ hơi buộc, vì vậy họ rút ngắn nó thành "lớp lồng nhau" mà không nhận ra sai lầm của họ. Giống như mọi người đều biết rằng Ruby không có các phương thức lớp, nhưng chúng ta vẫn gọi chúng là "các phương thức lớp", bởi vì việc xây dựng chính xác "các phương thức thể hiện của lớp đơn lớp của đối tượng lớp" quá bất tiện. Thật không may, điều này –

+0

... loại biệt ngữ phím tắt có thể dẫn đến sự nhầm lẫn đáng kể cho người ngoài và người mới. Chỉ cần có một cái nhìn tại tất cả các câu hỏi ở đây trên StackOverflow hỏi "Tôi biết cách làm X (chế nhạo, ghi đè, ghi đè, đặt bí danh, gói gọn, với các phương pháp bình thường, nhưng làm cách nào để thực hiện nó với các phương thức lớp?" Vì thuật ngữ lối tắt mà chúng tôi sử dụng, họ không nhận ra rằng họ thực sự đã biết câu trả lời cho câu hỏi của riêng họ, bởi vì * không có thứ gì như một phương thức lớp *. –

0

Có phải a được coi là phương pháp lớp cho lớp học A không?

class A 
    def self.a 
    raise "hi" 
    end 
    class B 
    def b 
     A::a 
    end 
    end 
end 

A::B.new.b 

Nếu bạn muốn giữ nó như là một phương pháp dụ, bạn sẽ rõ ràng là có cuộc gọi đến nó trên một thể hiện, ví dụ như A.new.a.

+0

Không, tôi thực sự có nghĩa là lớp học bên trong, phong cách báo. – nes1983

10

Đây chỉ là cho lulz:

class A 
    def a 
    puts "hello from a" 
    end 

    class B 
    def b 
     Module.nesting[1].new.a() 
    end 
    end 
end 
+0

Điều này chỉ có thể hoạt động nếu toàn bộ nội dung nằm trong mô-đun. –

3

Nếu bạn muốn lớp sau đó lồng nhau để mở rộng các lớp bên ngoài, sau đó làm như vậy:

class Outer 

    class Inner < Outer 
    def use_outer_method 
     outer_method("hi mom!") 
    end 
    end 

    def outer_method(foo) 
    puts foo 
    end 

end 

foo = Outer::Inner.new 
foo.use_outer_method  #<= "hi mom" 
foo.outer_method("hi dad!") #<= "hi dad" 
4

tôi thường làm một cái gì đó như thế này:

class A 
    def a 
    puts "hi" 
    end 

    def createB 
    B.new self 
    end 

    class B 
    def initialize(parent) 
     @parent=parent 
    end 

    def b 
     @parent.a 
    end 
    end 
end 

A.new.createB.b 
1

Cũng tùy thuộc vào hoàn cảnh của bạn, thực sự là giải pháp, một giải pháp khá dễ dàng. Ruby cho phép bắt các cuộc gọi phương thức mà đối tượng không bị bắt. Vì vậy, ví dụ của bạn, bạn có thể làm:

def class A 
    def a 
    raise "hi" #can't be reached 
    end 

    class B 
    def initialize() 
     @parent = A.new 
    end 

    def b 
     a() #does find method a. 
    end 

    def method_missing(*args) 
     if @parent.respond_to?(method) 
     @parent.send(*args) 
     else 
     super 
     end 
    end 
    end 
end 

Vì vậy, sau đó nếu bạn làm điều này:

A::B.new().b 

bạn nhận được:

!! #<RuntimeError: hi> 

Nó có lẽ là một cách dễ dàng hơn để làm một cái gì đó giống như một SubController chỉ xử lý các hoạt động nhất định, nhưng có thể dễ dàng gọi các phương thức điều khiển cơ bản (Bạn sẽ muốn gửi trong controller cha làm đối số trong initializer).

Rõ ràng điều này nên được sử dụng một cách tiết kiệm, và nó thực sự có thể gây nhầm lẫn nếu bạn sử dụng nó khắp nơi, nhưng nó có thể thực sự tuyệt vời để đơn giản hóa mã của bạn.

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