Something about Ruby Classes

The class Class

Lớp Class kế thừa trực tiếp từ Module và bao gồm tất cả hành vi của instance. Nói ngắn gọn thì, Module thường là nơi chứa các method của một hoặc nhiều Class, và Class thường được dùng để quản lí các properties của object.

Classes and ancestors

Để xem lớp cha mà Class kế thừa, ta có thể dùng superclass method:

>> Class.superclass
=> Module

>> Module.superclass
=> Object

Hoặc xem tất cả các lớp kế thừa theo danh sách tuần tự, ta dùng ancestors:

>> Class.ancestors
=> [Class, Module, Object, Kernel, BasicObject]

Classes are constants

Trong ruby, khi một Class mới được định nghĩa, thực chất chúng ta đang tạo một instance của lớp Class:

class Foo
end

>> Foo.class
=> Class

Ở vd trên chúng ta vừa định nghĩa một class là Foo, đồng nghĩa với việc nó chính là instance của lớp Class và chúng ta có thể dùng instance này qua constant Foo.

Theo logic này thì chúng ta có thể dùng cách khai báo khác, đó là tạo Foo như tạo một object bình thường:

Foo = Class.new

>> Foo.class
=> Class

How does Ruby looks for a method ?

class MyExample   
 def say_hello
   puts 'hello world'
 end
end

>> MyExample.ancestors
=> [MyExample, Object, Kernel, BasicObject]

>> MyExample.new.say_hello
=> hello world

>> MyExample.new.say_good_bye
=> NoMethodError

Khi gọi instance method say_hello từ instance của class MyExample, ruby sẽ tìm trong class MyExample method trùng tên, nếu có thì trả về kết quả phù hợp.

Tương tự khi gọi instance method say_good_bye, ruby trước tiên sẽ tìm method với tên tương ứng trong class MyExample, trường hợp này không tìm thấy nó sẽ tiếp tục tìm ngược lên các ancestors class khác đến tận class BasicObject, nếu vẫn không tìm thấy, kết quả trả về sẽ là NomethodError.

Include and Extend your Classes

Để dùng chung các method ở Module cho Class, ta có thể dùng include, extend, prepend methods. Bài viết này chúng ta sẽ chỉ tập trung vào 2 method đầu tiên, vì chúng phổ biến hơn method còn lại.

Include

Khi một Class include một Module, tất cả instance methods của Module đó sẽ trở thành instance methods của Class:

module RandomModule
  def say_thank_you
    puts 'thank you'  
  end
end

class RandomClass   
 include RandomModule
end

>> RandomClass.ancestors
=> [RandomClass, RandomModule, Object, Kernel, BasicObject]

>> RandomClass.new.say_thank_you
=> thank you

Như vd ở trên ta có thể thấy ancestors class của RandomClass đã bao gồm RandomModule. Khi gọi method say_thank_you ở instance của RandomClass, ruby sẽ vào RandomClass để check method tương ứng, không có thì sẽ tiếp tục tìm lần lượt các class mà RandomClass kế thừa, đầu tiên là RandomModule. Ở đây method tương ứng đã được tìm thấy và trả về kết quả mong muốn.

Extend

Dù chung mục đích là dùng chung method giữa Class và Module, nhưng extend lại khác hoàn toàn include. Nếu như include dùng để thêm các instance method, thì extend có nhiệm vụ thêm các class method:

module RandomModule
  def say_thank_you
    puts 'thank you'  
  end
end

class RandomClass   
 extend RandomModule
end

>> RandomClass.new.say_thank_you
=> NoMethodError

>> RandomClass.say_thank_you
=> thank you

>> RandomClass.ancestors
=> [RandomClass, Object, Kernel, BasicObject]

Sau khi extend RandomModule vào RandomClass, chúng ta có thể dùng method say_thank_you như là một class method. Khi gọi method say_thank_you từ instance của RandomClass, ta nhận được kết quả NoMethodError. Nhưng khi gọi trực tiếp từ class RandomClass, kết quả trả về hoàn toàn phù hợp.

Chúng ta cũng có thể dùng extend cho duy nhất một class instance cụ thể:

module RandomModule
  def say_thank_you
    puts 'thank you'  
  end
end

class RandomClass
end

>> RandomClass.new.say_thank_you
=> NoMethodError

>> new_instance = RandomClass.new
>> new_instance.extend RandomModule
>> new_instance.say_thank_you
=> thank you

Classes are open

Chúng ta hoàn toàn có thể thêm hoặc sửa các method của các ancestor class, của riêng chúng ta hay thậm chí là class có sẵn của Ruby:

class String
  def tell_my_size
    self.size
  end

  def reverse
    self.size
  end
end

>> my_string = 'hello world'
>> my_string.tell_my_size
=> 11

>> my_string.reverse
=> 11

Ở vd này chúng ta đã tạo mới một instance method tell_my_size và override lại method có sẵn reverse của Class String của Ruby. Mặc dù cách làm này khá hữu dụng trong 1 số trường hợp, nhưng chúng ta không nên lạm dụng và thật thận trọng trước khi thêm mới hoặc override lại các method có sẵn của Ruby.

Summary

Bài viết nhằm chia sẻ một vài kiến thức basic khá thú vị của Class trong Ruby, bài viết còn nhiều thiếu sót, cảm ơn bạn đã dành thời gian theo dõi.

Nguồn: https://dev.to/olivdums/what-i-didn-t-know-about-ruby-classes-48bd


All Rights Reserved