Có một bí danh cho một phương thức lớp không?


10

Hãy xem xét các lớp sau:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
end

Đây không phải là vấn đề và bạn có thể gọi Foo.new.a_new_inst_methodmà không có vấn đề.

Tôi muốn khả năng có một phương thức lớp như Foo.add_widget(*items)và bí danh nó để tôi có thể làm một cái gì đó như:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

Vì vậy, về cơ bản, nó có kiểu "ruby" 1.minute2.minutesvì vậy tôi muốn đặt bí danh cho một Foo.add_widgetcuộc gọi để gọi Foo.add_widgetscác phương thức chính xác. Tôi biết tôi có thể bọc nó nhưng tôi cảm thấy mình có thể làm điều này một cách sạch sẽ hơn.

Hãy xem xét nỗ lực của tôi trong việc thử một cái gì đó như thế này:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
  alias_method :a_new_class_method, :a_class_method
end

Tuy nhiên, tôi nhận được lỗi sau:

NameError (undefined method `a_class_method' for class `Foo')

Và có vẻ như điều này không hoạt động đối với các phương thức lớp. Làm thế nào để tôi đi về làm điều này?

Câu trả lời:


9

alias_methodbí danh một phương thức cá thể của người nhận. Các phương thức lớp thực sự là các phương thức cá thể được định nghĩa trên lớp singleton của một lớp.

class MyClass
  def self.a
    "Hello World!"
  end
end

method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)

method_1 == method_2
#=> true

Để bí danh một phương thức cá thể được xác định trên lớp singleton, bạn có thể mở nó bằng class << objectcú pháp.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Hoặc bạn có thể tham khảo nó trực tiếp bằng singleton_classphương pháp.

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Nếu bạn vẫn còn trong bối cảnh lớp selfsẽ tham khảo lớp. Vì vậy, ở trên cũng có thể được viết là:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end

Hoặc là

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end

Hoặc kết hợp cả hai.


5

Bạn có thể gói các phương thức lớp và các alias_methodcuộc gọi của chúng vào một mô-đun riêng biệt và kết hợp mô-đun đó vào lớp của bạn thông qua extend:

class Foo
  def an_inst_method
    'instance method'
  end
  alias_method :a_new_inst_method, :an_inst_method

  module ClassMethods
    def a_class_method
      'class method'
    end
    alias_method :a_new_class_method, :a_class_method
  end

  extend ClassMethods
end

Chào! Tôi quên mất extend ClassMethodsgiải pháp. +1
aarona

4

Điều quan trọng cần hiểu là không có thứ gọi là phương thức lớp trong Ruby.

Một phương thức lớp thực sự chỉ là một phương thức đơn lẻ. Không có gì đặc biệt về các phương thức lớp. Mọi đối tượng có thể có các phương thức singleton. Chúng tôi chỉ gọi chúng là "phương thức lớp" khi đối tượng là Classvì "phương thức singleton của một thể hiện Class" quá dài và khó sử dụng.

Chờ đợi! Tôi đã nói "phương pháp singleton"?

Một điều quan trọng khác để hiểu là không có phương pháp đơn lẻ nào trong Ruby.

Một phương thức singleton thực sự chỉ là một phương thức cũ nhàm chán thông thường của lớp singleton. Không có gì đặc biệt về các phương pháp singleton. Chúng chỉ là các phương thức cá thể như bất kỳ phương thức cá thể nào khác.

Trong thực tế, Ruby chỉ có các phương thức cá thể. Không có hàm, không có hàm tạo, không có phương thức tĩnh, không có phương thức lớp, không có hàm mô-đun, không có phương thức singleton.

Câu hỏi không phải là "đây có phải là một phương thức lớp không, đây có phải là một phương thức đơn lẻ" không, mà là " phương thức này được định nghĩa trong mô-đun nào?"

"Các phương thức Singleton" là các phương thức thực sự được định nghĩa trong lớp singleton. Cú pháp để truy cập lớp singleton foo

class << foo
end

Ngoài ra còn có một phương thức Object#singleton_classtrả về lớp singleton của một đối tượng.

Tại sao tôi lại quyết liệt tập trung vào thực tế rằng mọi phương thức là một phương thức cá thể và các phương thức lớp đó không tồn tại? Bởi vì điều đó có nghĩa là mô hình đối tượng của Ruby đơn giản hơn nhiều so với mọi người nghĩ! Rốt cuộc, trong câu hỏi của bạn, bạn đã chỉ ra rằng bạn biết cách đặt bí danh cho các phương thức cá thể, nhưng bạn nói rằng bạn không biết làm thế nào để bí danh các phương thức lớp. Nhưng, đó là sai! Bạn làm biết làm thế nào để phương pháp lớp học bí danh, vì họ chỉ là phương pháp dụ . Nếu bạn đã được dạy thực tế này đúng cách, bạn sẽ không bao giờ cần phải hỏi câu hỏi này!

Khi bạn hiểu rằng mọi phương thức là một phương thức cá thể và rằng cái mà chúng ta gọi là "phương thức singleton" chỉ là phương thức cá thể của lớp singleton, giải pháp trở nên rõ ràng:

singleton_class.alias_method :a_new_class_method, :a_class_method

Lưu ý: khi tôi viết ở trên rằng "không có thứ gọi là X", ý tôi là "không có thứ X như ngôn ngữ Ruby ". Điều đó không có nghĩa là những khái niệm đó không tồn tại trong cộng đồng Ruby .

Chúng ta thường nói về "phương thức singleton" và "phương thức lớp", đơn giản vì nó dễ hơn nói về "phương thức cá thể của lớp singleton" hoặc "phương thức cá thể của lớp singleton của một đối tượng xảy ra là một thể hiện của Classlớp ". Có nhiều phương pháp thậm chí như Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, và Module#module_functiontrong thư viện lõi Ruby. Nhưng điều quan trọng cần nhớ là đó không phải là khái niệm ngôn ngữ. Đó là những khái niệm cộng đồng chỉ tồn tại trong đầu chúng ta và trong tên của một số phương thức thư viện.


2

OK, có vẻ như tôi có thể làm một cái gì đó như thế này và nó sẽ hoạt động:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    alias_method :a_new_class_method, :a_class_method
  end
end

Foo.a_class_method # => "class method" 
Foo.a_new_class_method # => "class method"

Nếu bất cứ ai có bất kỳ thông tin hữu ích nào về ngôn ngữ Ruby ở đây và muốn gửi câu trả lời toàn diện, tôi sẽ cung cấp cho bạn +1.


1
Khi bạn làm class << selftheo sau, alias_method :a_new_class_method, :a_class_methodbạn thực sự gọi alias_methodlớp singleton của Foo. Một cách viết khác là: singleton_class.alias_method :a_new_class_method, :a_class_methodtrong bối cảnh lớp học.
3limin4t0r

Bạn muốn gì hơn từ một câu trả lời? Ý tôi là, đây có thể là giải pháp sạch nhất.
Dave Newton

@ 3limin4t0r nếu bạn trả lời, tôi sẽ +1 nó. Cảm ơn cho thông tin thêm này.
aarona

@DaveNewton bạn đúng nhưng vì tôi cũng có một triết lý rằng nếu ai đó có thể cung cấp bất kỳ thông tin nào có ý nghĩa hơn cho một vấn đề ngay cả khi nó gián tiếp giải quyết vấn đề, tôi nghĩ rằng cũng nên được khen thưởng.
aarona

2

alias_methodhoạt động theo thể hiện, vì vậy bạn cần đi sâu hơn một cấp độ và vận hành theo Classthể hiện, hoặc siêu dữ liệu của lớp . Ruby có một mô hình đối tượng hoang dã có thể phá vỡ não bộ, nhưng nó cũng mang lại cho bạn rất nhiều sức mạnh:

class Foo
  def an_inst_method
    'instance method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    def a_class_method
      'class method'
    end

    alias_method :a_new_class_method, :a_class_method
  end
end

Tôi đã làm việc với ruby ​​trong bối cảnh đường ray trong khoảng một thập kỷ nhưng chỉ gần đây mới bắt đầu đi sâu vào mô hình đối tượng. Có rất nhiều thứ hay ho có sẵn!
aarona
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.