2012-07-17 6 views
5

Trong Ruby, tôi đang cố tạo một lớp, dựa trên giá trị được đưa ra trong quá trình khởi tạo sẽ kế thừa từ một trong các mô-đun sau. Tôi muốn tạo ra một mô-đun cơ bản mà cả hai mô-đun này kế thừa từ đó chứa các phương thức chung sử dụng các hằng số được định nghĩa trong các mô-đun kế thừa nó. Ví dụ:Kế thừa hằng số bên trong mô-đun Ruby

module BaseMod 
    def what_am_i 
    puts OUTPUT 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize type 
    if type =~ /short/i 
     extend Short 
    else 
     extend Tall 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 

Vấn đề của tôi là khi "p.what_am_i" được gọi là tôi nhận được lỗi sau:

NameError: uninitialized constant BaseMod::OUTPUT 
    const_missing at org/jruby/RubyModule.java:2642 
     what_am_i at test_logic2.rb:3 
     (root) at test_logic2.rb:28 

Tôi cũng tự hỏi nếu có một cách tốt hơn để đi về việc này.

Trả lời

2

Để có được liên tục trong tình huống của bạn, bạn phải viết một cái gì đó như thế này:

module Tall 
::OUTPUT = "I am tall" 
include BaseMod 
end 

Tuy nhiên nhận thấy rằng bạn đang xác định lại liên tục với lời tuyên bố của các mô-đun ngắn. Cho rằng bạn sẽ luôn luôn nhận được "Tôi ngắn".

Vì vậy, để làm điều đó một cách chính xác bạn nên thử:

module BaseMod 
OUTPUT="Before" 
def what_am_i 
    puts OUTPUT 
end 
end 

module Tall 
def self.extended(k) 
    OUTPUT.replace "I am tall" 
end 
include BaseMod 
end 

module Short 
def self.extended(k) 
    OUTPUT.replace "I am short" 
end 
include BaseMod 
end 

K

0

Dường như khi bạn tin nhắn mà người p của bạn với thông điệp #what_am_i, người phiên dịch tìm kiếm các phương pháp thực hiện liên tiếp cao hơn và cao hơn trong tổ tiên lớp, và cuối cùng tìm thấy nó trong BaseMod, nhưng ở cấp độ đó, hằng số OUTPUT không được định nghĩa nữa. Vì vậy, tôi nghĩ rằng Ruby tiếp tục tìm kiếm OUTPUT hằng số đi trở lên trong hệ thống phân cấp, nhưng không nghĩ về việc nhìn xuống dưới, trong các mô-đun Cao và Ngắn nơi nó được xác định. Tinh thần là, ngay cả khi bạn bao gồm rất nhiều submodules, họ không đi vào một đống mà tất cả các hằng số có thể truy cập cho tất cả mọi người, nhưng thay vào đó họ giữ thứ bậc của họ theo thứ tự ngược lại của họ (xem Tall.Ancestors). Ở mọi cấp độ, chỉ có thể truy cập vào cùng một cấp độ hoặc các mức cao hơn. Tôi sẽ giải quyết vấn đề của bạn theo cách sau:

module Personhood 
    def what_am_i; @output end 
end 

class Tall 
    include Personhood 
    def initialize 
     @output = "I am tall" 
    end 
    end 
end 

class Short 
    include Personhood 
    def initialize 
     @output = "I am short" 
    end 
    end 
end 

def Person(type) 
    if type =~ /short/i 
    Short.new 
    else 
    Tall.new 
    end 
end 

pete = Person "short" 
pete.what_am_i 
=> I am short 

Tôi đã bỏ một hằng số ủng hộ các biến mẫu. Trong Ruby, không có hằng số thực nào. Tall và Short được tạo thành các lớp và Person được tạo thành phương thức khởi tạo, trả về lớp Tall hoặc Short tùy thuộc vào đầu vào của nó. Đó là cách tôi cảm thấy nó nên được thực hiện.

1

Tôi sẽ mang thêm một tùy chọn nữa vào bảng. Tôi không hoàn toàn chắc chắn những gì phức tạp của mình, trường hợp thực tế là, vì vậy đây là lựa chọn của tôi:

module BaseMod 
    def what_am_i 
    puts output 
    end 
end 

module Tall 
    include BaseMod 
    def self.extended klass 
    define_method :output do 
     "I am tall" 
    end 
    end 
end 

module Short 
    include BaseMod 
    def self.extended klass 
    define_method :output do 
     "I am short" 
    end 
    end 
end 

class Person 
    def initialize type 
    extend (type =~ /short/i ? Short : Tall) # Because I didn't wanna type all those lines 
    end 
end 

p = Person.new "short" 
p.what_am_i 

Xin lưu ý rằng tình trạng này, bạn có thể chỉ là một cách dễ dàng làm được điều này:

module Tall 
    include BaseMod 
    def output 
    "I am tall" 
    end 
end 

Nhưng tôi không biết nếu điều đó thực sự sẽ giúp bạn.

+0

cách thú vị để làm điều đó. –

+0

@BorisStitnicky tùy thuộc vào những gì bạn muốn xây dựng, một phương pháp có thể có ý nghĩa hơn một biến mẫu. YMMV :) – Trevoke

4
module BaseMod 
    def what_am_i 
    puts self.class::OUTPUT 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize(type) 
    if type =~ /short/i 
     self.class.send(:include, Short) 
    else 
     self.class.send(:include, Tall) 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 

Edit: Đoạn mã trên không thực sự làm việc:

p = Person.new "short" 
p.what_am_i 
>> I am short 
p = Person.new "tall" 
p.what_am_i 
>> I am tall 
p = Person.new "short" 
p.what_am_i 
>> I am tall 

Dưới đây là một nỗ lực:

module BaseMod 
    def self.included(base) 
    base.send(:define_method, :what_am_i) do 
     puts base::OUTPUT 
    end 
    end 
end 

module Tall 
    OUTPUT = "I am tall" 
    include BaseMod 
end 

module Short 
    OUTPUT = "I am short" 
    include BaseMod 
end 

class Person 
    def initialize type 
    if type =~ /short/i 
     extend Short 
    else 
     extend Tall 
    end 
    end 
end 

p = Person.new "short" 
p.what_am_i 
p = Person.new "tall" 
p.what_am_i 
p = Person.new "short" 
p.what_am_i 
+0

Bí quyết tuyệt vời, cảm ơn. Nhưng cá nhân, như một sự lựa chọn thiết kế, tôi vẫn sẽ tránh sử dụng hằng số trong các trường hợp như thế này. –

+0

Tôi có thể thấy nó theo một trong hai cách. Các hằng số phù hợp với quan điểm của mô-đun Cao và Ngắn. Hằng số này là kỳ lạ từ quan điểm của Person, nhưng đó không phải là nơi mà phương thức what_am_i nên sống. Trong mọi trường hợp, mã của tôi không hoạt động đúng, vì vậy tôi đã thêm một giải pháp khác. –

+0

Tôi hiểu. Tôi đã không thử nó, vì vậy tôi đã không nhận thấy nó không hoạt động :) –