2013-04-09 40 views
32

Tôi đã triển khai một biểu mẫu bao gồm một trình đơn thả xuống được mã hóa cứng và tôi đã tự hỏi giải pháp nào là tốt nhất, tôi biết cả hai cách tiếp xúc dưới đây. :Phương thức lớp vs hằng số trong Ruby/Rails

class Example 

    # Options for Example. 
    self.options 
    [ 'Yes', 'No', 'Not sure' ] 
    end 
end 

được gọi bởi Example.options, nhưng tôi biết nó có thể làm như sau cũng như:

class Example 

    # Options for Example. 
    OPTIONS = [ 'Yes', 'No', 'Not sure' ] 
end 

đó sẽ được gọi với Example::OPTIONS.

Câu hỏi đặt ra là, liệu đây có phải là cách tốt hay không quan trọng?

+0

Phương pháp được chấp nhận chung là sau khi Upercase với các ý kiến ​​là một hình thức tài liệu hướng dẫn cho người dùng rằng đây là một hằng số –

+2

Không liên quan đến một câu trả lời có thể, tôi sẽ đề nghị sử dụng những biểu tượng trên chuỗi trừ khi mã của bạn đặc biệt cần chuỗi. Do đó '[: yes,: no,: not_sure]' –

Trả lời

33

Cách thứ hai tốt hơn. Nếu nó là một phương thức, một mảng mới và các chuỗi mới sẽ được tạo ra mỗi khi nó được gọi, đó là một sự lãng phí tài nguyên.

+1

Đẹp nhất ở đó! Cảm ơn :) –

+0

Fantastic, +10, nếu tôi có thể ;-) –

+0

+1 Cũng gọi 'Example.methods' sẽ cho biết các tùy chọn là một phương thức, khi bạn biết là một hằng số lớp. Đó là một mẹo khác để tạo mã nhất quán. – nicooga

26

TL; DR: Tùy theo. Các giá trị có nghĩa là được sử dụng bên ngoài lớp học? Họ có thể trở nên năng động không? Họ có thể thay đổi cho các lớp con không?

Khi @sawa viết, nhược điểm của phương thức (được viết theo cách này) là một mảng và chuỗi mới được tạo ra mỗi lần.

Cách tốt hơn để viết nó sẽ là:

class Example 
    def self.options 
    @options ||= ['Yes', 'No', 'Not sure'] 
    end 
end 

Mảng được lưu trữ trong trường hợp biến @options, để tránh tạo ra một mảng mới mỗi lần.

Bằng văn bản theo cách này, phương pháp này rất giống với hằng số.

Một sự khác biệt quan trọng là nếu Example được subclassed, nó sẽ tự nhiên hơn để tinh chỉnh các phương pháp options hơn hằng số OPTIONS:

class Parent < Example 
    def self.options 
    @options ||= [*super, 'Extra'] 
    end 
end 

Để làm được điều gì đó tương tự với các hằng số là khó khăn. Hãy tưởng tượng rằng danh sách các tùy chọn được sử dụng trong một phương pháp học, điều này sẽ trông giống như:

class Example 
    OPTIONS = ['Yes', 'No', 'Not sure'] 

    def self.foo(arg) 
    puts "Available options:", 
      self::OPTIONS # The self:: is needed here 
    # ... 
    end 
end 

class Parent < Example 
    OPTIONS = [*superclass::OPTIONS, 'Extra'] 
end 

Điều khó khăn về hằng số, là self::OPTIONSOPTIONS không phải là lúc nào cũng giống nhau, trong khi self.optionsoptions đều giống nhau. Hằng số thường được sử dụng mà không chỉ định phạm vi (ví dụ: OPTIONS thay vì self::OPTIONS) và kế thừa sẽ không hoạt động trong trường hợp đó.

Lưu ý rằng phương pháp cho bạn cơ hội để tạo kết quả động (tức là trả lại các kết quả khác nhau tùy thuộc vào các trường hợp khác) mà không thay đổi API.

Lưu ý cuối cùng: Tôi khuyên bạn nên gọi số freeze trên mảng của mình để tránh bất kỳ ai sửa đổi nó.

+0

Bạn vẫn có thể làm điều tương tự với các hằng số: 'Example :: Options = [" Yes "," No "," Not sure "]; Parent :: Options = [* Example :: Options, "Extra"] '. Sự khác biệt duy nhất là bạn phải viết một cách rõ ràng lớp cha thay vì sử dụng 'super'. – sawa

+2

@sawa: Thật vậy, bạn có thể (và bạn có thể sử dụng 'superclass' thay vì viết một cách rõ ràng lớp cha), nhưng việc truy cập các hằng số có thể phức tạp. Đã chỉnh sửa câu trả lời của tôi. –

+0

Ý tưởng liên quan trong câu hỏi là trực tiếp gọi hằng số như 'Example :: OPTIONS' hoặc' Parent :: OPTIONS', hoặc 'OPTIONS'. Tôi không hiểu tại sao bạn định nghĩa 'self.foo' để gọi họ. – sawa

6

Những gì tôi thường làm là có một kết hợp của kỹ thuật nêu trên:

class Player 
    JURISDICTIONS = %i(de uk ru) 

    def self.jurisdictions 
     JURISDICTIONS 
    end 
end 

Nó có vài ưu điểm:

  • Nó cung cấp một giao diện sạch sẽ, đóng gói một hằng số (bạn gọi Player.jurisdictions thay vì Player::JURISDICTIONS).
  • Có thể thêm logic bổ sung sau bằng cách thay đổi phương thức.
  • Phương pháp có thể được phân tích trong các thử nghiệm.

IMHO, hiệu suất không quan trọng ở đây.

Cập nhật: liên tục có thể bee ẩn bằng phương pháp private_constant (http://ruby-doc.org/core-2.3.0/Module.html#method-i-private_constant)

+2

Bạn có lỗi đánh máy phải là bản thân. – Sunny

+0

Cảm ơn bạn! Đã sửa. –

1

Để tinh chỉnh thêm gợi ý Artur của tôi sẽ đi với một biến lớp để che giấu tầm nhìn của hằng số.

class Player 
    @@jurisdictions = %i(de uk ru) 

    def self.jurisdictions 
    @@jurisdictions 
    end 
end 
+0

Hoạt động tốt hơn, đồng ý! Nhưng cho đến nay tôi đã không thể giải quyết vấn đề thừa kế được mô tả ở đây: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ –

+0

Sau khi tôi viết bài này Tôi phát hiện ra bạn cũng nên xem xét các biến thể hiện cấp lớp: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ –

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