2010-10-23 16 views
9

Tôi mới sử dụng Ruby. Một ví dụ đơn giản, những gì tôi cần:Các giải pháp thay thế cho các lớp trừu tượng trong Ruby?

class Animal 
    abstract eat() 

class Cat < Animal 
    eat(): 
    implementation 

class Dog < Animal 
    eat(): 
    implementation 

Nói cách khác, phương thức eat() phải được yêu cầu cho tất cả các lớp mở rộng Động vật.

Trong JAVA tôi chỉ sử dụng một lớp trừu tượng, nhưng sau khi thực hiện một số nghiên cứu, tôi thấy rằng nhiều người không sử dụng nó trong Ruby và mixin/modules được đề nghị thay thế.

Tuy nhiên, tôi không hiểu, nếu mô-đun có thể làm nhiều hơn là chỉ bao gồm một phương pháp bổ sung. Để được chính xác, các module có thể thiết lập các yêu cầu cho các lớp mà các phương thức mà chúng phải thực hiện (nếu có, một ví dụ sẽ được đánh giá cao)?

Tóm lại, tôi nên sử dụng điều gì trong trường hợp này, khi tôi muốn chắc chắn rằng tất cả các lớp cùng loại có phương pháp cụ thể và triển khai chúng theo cách riêng của chúng?

+1

Trích dẫn gì về 'NotImplementedError' và bộ phận hạ cánh của máy bay? –

Trả lời

9

Ruby không cung cấp chức năng này, không. Bạn có trách nhiệm đảm bảo rằng các lớp học của bạn thực hiện những gì họ nên thực hiện.

Một phần lý do khiến Ruby không thể mở chức năng như vậy, và Ruby hỗ trợ tải mã tùy ý trong thời gian chạy, vì vậy chúng tôi không thể biết một lớp có triển khai giao diện nhất định hay không nó.

Giả sử một Animal phải có một phương pháp eat, và tôi thực hiện như sau:

class Cat < Animal 
    def talk 
    puts "meow" 
    end 
end 

class Cat 
    def eat 
    puts "om nom nom" 
    end 
end 

Đến cuối tập tin đó, Cat sẽ phải định nghĩa eat nó, bởi vì các lớp học Ruby có thể mở cửa trở lại và sửa đổi nhiều lần . Nếu lỗi mã ra sau định nghĩa đầu tiên vì eat chưa được xác định? Việc thực hiện đó sẽ làm tổn thương nhiều hơn nó sẽ giúp ích, vì các lớp mở lại là phổ biến, ngay cả khi ví dụ này được giả tạo. Nó có nên lỗi khi phương thức eat được gọi và không tồn tại, vì vậy chúng ta có thể chắc chắn rằng nó được định nghĩa khi chúng ta cần nó? Vâng, nếu phương pháp bị thiếu, thì dù sao, sẽ xảy ra. Người phiên dịch không bao giờ có thể biết một định nghĩa lớp khác có đang trên đường không, vì vậy nó không bao giờ có thể cắt đứt bạn cho đến khi phương thức này được gọi thực sự.

Tóm lại, các siêu lớp đơn giản không thể yêu cầu một phương thức được định nghĩa trong Ruby, vì bản chất động của các lớp mâu thuẫn với một mục tiêu như vậy.

Xin lỗi! Đây là một nơi mà thử nghiệm đơn vị có thể có ích, tuy nhiên, để đảm bảo rằng các lớp con của bạn làm những gì chúng được cho là đang làm.

+0

+1 cho "om nom nom": D Bạn đã thấy [việc triển khai] (http://www.facebook.com/video/video.php?v=1055625287695) chưa? – edgerunner

+0

Tôi tin rằng bạn không thể làm được điều đó trong Ruby, nhưng tôi nghi ngờ việc biên dịch có liên quan đến nó. Python có một mẫu thiết kế lớp cơ sở trừu tượng chung sử dụng metaclass "ABCMeta", và nó không yêu cầu biên dịch. –

+0

@SteveZelaznik: Công bằng, chỉnh sửa :) Điều quan trọng là nó hỗ trợ lớp mở lại và tải mã khi chạy, mà * là * cách dễ dàng hơn trong môi trường giải nghĩa, nhưng, vâng, probs không thể. Trong mọi trường hợp, Python không hỗ trợ lớp mở lại, do đó, nó miễn phí để triển khai các lớp trừu tượng :) – Matchu

1

Không tương đương với các lớp trừu tượng trong Ruby. Chủ yếu là vì Ruby được nhập động, có nghĩa là khái niệm về các lớp trừu tượng không thực sự áp dụng.

2

Bạn chỉ có thể sử dụng các phương thức trống hoặc làm cho chúng tăng lỗi để buộc các lớp con triển khai chúng.

class Base 
    def abstract_method 
    end 

    def mandatory_abstract_method 
    raise NotImplementedError.new("You must implement this") 
    end 
end 

Phía xuống là điều này chỉ thực thi khi phương pháp này thực sự được gọi. Ruby là một ngôn ngữ động và nó không có bất kỳ kiểm tra thời gian biên dịch nào.

19

Sử dụng mô-đun xác định các phương pháp phải được triển khai.

module Animal 
    def eat 
    raise NotImplementedError 
    end 
end 

class Cat 
    include Animal 

    def eat 
    "Om nom nom" 
    end 
end 

class Dog 
    include Animal 
end 

c = Cat.new 
c.eat # => "Om nom nom" 

d = Dog.new 
d.eat # => NotImplementedError 
0

Nếu bạn thực sự muốn triển khai trừu tượng thì bạn sử dụng đá quý trừu tượng.

sudo gem install abstraction 

Ví dụ tham chiếu Ví dụ từ Abstraction gem WIKI.

class Car 
    abstract 

    def go_forward 
    # ... 
end 
end 

Car.new 
> AbstractClassError: Car is an abstract class and cannot be instantiated 

class Convertible < Car 
    def door_count 
    2 
    end 
end 

class Sedan < Car 
    def door_count 
    4 
    end 
end 

Convertible.new # => #<Convertible:0x8fdf4> 
+0

Điều này chỉ ngăn cản sự khởi tạo của lớp trừu tượng. Bây giờ nó đảm bảo các phương thức trừu tượng được thực hiện trong các lớp con cụ thể. –

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