Eigenclasses trong ruby - Ẩn số thú vị
Khi làm việc với ruby and rails chúng ta phải làm việc rất nhiều với class, chính vì vậy mà việc hiểu và sử dụng class trong ruby là rất quan trọng. Bài viết này mình sẽ tìm hiểu về một khái niệm liên quan đến class trong ruby đó là Eigenclasses. Trước khi đi sâu hơn về class, hãy cùng tìm hiểu ...
Khi làm việc với ruby and rails chúng ta phải làm việc rất nhiều với class, chính vì vậy mà việc hiểu và sử dụng class trong ruby là rất quan trọng. Bài viết này mình sẽ tìm hiểu về một khái niệm liên quan đến class trong ruby đó là Eigenclasses.
Trước khi đi sâu hơn về class, hãy cùng tìm hiểu về singleton method trong ruby. Có nhiều cách định nghĩa về singleton method trong ruby nhưng mình hiểu đơn giản là:
Ruby cho phép ta thêm một method vào một đối tượng
VD: Ta có một đối tượng str = "hello"
Chúng ta có thể thêm một method vào đối tượng str này bằng cách khai báo:
def str.method1 puts "this is method 1" end
Như vậy khi ta gọi str.method1 => kết quả in ra là "this is method 1". Tuy nhiên, chỉ có đối tượng str mới có thể gọi method 1, với những object khai báo và khởi tạo bằng string khác sẽ không thể gọi method1.
str2 = "hello2" str2.method1 # No method 'method1'
Chúng ta cần nhớ lại là mọi thứ trong ruby là đối tượng kể cả class. Như vậy khi ta gọi một class method cũng giống như việc ta gọi một object của đối tượng như ví dụ phía trên.
class A; end # khai báo một method cho class A cũng giống như khai báo cho đối tượng def A.method1 puts "this is method of A" end A.method1 # 'this is method of A'
Và sự thực là class method chính là singleton method của class. Ta cũng có thể thay tên của class như ví dụ trên bằng từ khóa self
class A def self.method1 puts "this is method of A" end end
Như vậy chúng ta luôn định nghĩa singleton method giống như mẫu
def object.method # implement method here end
Sau khi đã tìm hiểu cơ bản về method trong ruby, phần này ta sẽ đi sâu tìm hiểu về khái niệm Eigenclasses.
Ta có một class
class MyClass def my_method; end end obj = MyClass.new obj.my_method
Khi ta gọi hàm my_method từ đối tượng obj ruby sẽ tìm trực tiếp từ class MyClass, nếu không tìm thấy nó sẽ tìm kiếm từ các class cha mà MyClass kế thừa. Trong trường hợp này thì nó sẽ tìm thấy luôn trong class MyClass.
Nhưng giả sử chúng ta khai báo singleton method cho obj
def obj.my_singleton_method; end
Nhìn vào sơ đồ
Ta tự hỏi cái method my_singleton_method nó nằm ở đâu vậy (???). Nó không thể nằm trong obj được vì obj không phải là 1 class, cũng không thể nằm trong class MyClass được vì như vậy mọi instance của MyClass sẽ gọi được hàm my_singleton_method trong khi thực tế thì chỉ có obj mới gọi được method này thôi, nó cũng không thể nằm trong các class mà MyClass kế thừa cũng vì lý do này. Vậy thì ở đâu ???
Đây chính là lúc thằng eigenclass bị phơi bày ra.
Khi chúng ra hỏi về class của một object, ta thường nghĩ đến class đã định nghĩa nhưng sự thật object có một class ẩn gọi là eigenclass.
Ta có thể thêm code cho eigenclass với cách khai báo sau:
class << object # your code here end
Chúng ta sẽ đi vào các ví dụ sau để hiểu sâu hơn về thằng này.
class C def a_method 'C#a_method()' end end class D < C; end obj = D.new obj.a_method # kết quả : 'C#a_method()'
Khi ta gọi hàm a_method ruby sẽ tìm kiếm từ class D, sau khi không tìm kiếm thấy method a_method nó sẽ đi lên class C để tìm kiếm vì D kế thừa C
Sơ đồ sẽ như sau:
Tiếp theo để dễ dàng cho việc tìm hiểu eigenclass chúng ta định nghĩa một method sau ở class Object
class Object def eigenclass class << self; self; end end end "string".eigenclass # kết quả là #<Class:#<String:0x00005593e58c3920>>
Nhìn vào kết quả trên ta thấy ruby trả về eigenclass của một đối tượng và để phân biệt nó thêm "#" vào phía trước. Như vậy tương tự eigenclass của C là #C, của D là #D, của obj là #obj. Khi ta định nghĩa một method cho obj như sau:
class << obj def a_singleton_method 'obj#a_singleton_method()' end end obj.a_singleton_method # kết quả: 'obj#a_singleton_method()' obj.eigenclass.superclass # => D
Sơ đồ lúc này sẽ như sau:
Nhìn vào sơ đồ ta có thể trả lời câu hỏi phía trên đó là hàm a_singleton_method thực tế là nằm ở eigenclass của obj đó là #obj