Advanced Modules in Ruby
Bài đăng này đã không được cập nhật trong 8 năm
Module
Như các bạn đã biết, Module
là một tập hợp các method, class và constant. Module
mang lại 2 lợi ích chủ yếu:
- Cung cấp một
namespace
và tránh việc trùng lặp tên - Thực hiện
mixin
dễ dàng
Module thực hiện mixin
bằng cách sử dụng method include
để include các method của nó vào trong một class, khi đó, class này sẽ có khả năng truy cập vào các instance method bên trong module đó. Hãy xem một ví dụ sau đây để thấy rõ hơn về điều đó:
module Animal
def say
puts "Hello world!"
end
end
class Cat
include Animal
end
cat = Cat.new
cat.say
# Hello world!
Sau đây, tôi sẽ giới thiệu về một số kĩ thuật nâng cao khi sử dụng module.
Included
callback
included
là một callback mà Ruby gọi nó mỗi khi một module được include vào một module/class khác. Chúng ta cùng đến với một ví dụ như sau:
module Animal
def self.included(base)
puts "Animal has been included in class #{base}"
end
end
class Cat
include Animal
end
Output:
Foo has been included in class Bar
Chú ý rằng, included
được định nghĩa ở trong module sử dụng keyword self
, với tham số là base
- target class.
Extend
method
Như đã trình bày ở trên, include
có khả năng chia sẻ hành vi thông qua các module bằng cách mixin
các methods từ một module vào một class.
Tuy nhiên, include
có một hạn chế: nó chỉ có thể thêm instance method
cho class chứ không thêm được class method
. Cùng xem một ví dụ sau đây:
module Animal
def self.say
puts "Hello world!"
end
end
class Cat
include Animal
end
Cat.say
Output:
NoMethodError: undefined method `say' for Cat:Class
Như các bạn có thể thấy, chúng ta nhận được NoMethodError
khi gọi method của module từ class.
Nhưng có những trường hợp bạn sẽ muốn include một vài method từ một module như một class method vào trong một class. Đó là khi bạn sẽ thấy extend
trở nên hữu dụng (yeah).
extend
method làm việc tương tự như include
, nhưng không giống như include
, bạn có thể sử dụng nó để extend bất cứ object nào bằng cách thêm các method và các constant từ một module.
Ví dụ như sau:
module Animal
def say
puts "Hello world!"
end
end
class Cat
end
cat = Cat.new
cat.extend Animal
cat.say
Output:
Hello world!
Điều đáng chú ý ở đây là extend
làm việc ở mọi nơi: bên trong một class/module và trên các instance cụ thể. Còn include
thì không thể sử dụng được trên các instance cụ thể. Như ví dụ trên thì cat.include Animal
sẽ raise ra một lỗi NoMethodError: undefined method 'include' for #<Cat:0x0000000d880ad8>
.
Theo một nghĩa nào đó, extend
có thể được sử dụng để bắt chước chức năng của method include
. Khi bạn thêm một câu lệnh include
vào trong một class, Ruby đảm bảo rằng tất cả những instance của class đó sẽ có những method được định nghĩa bên trong module đã được include.
Tuy nhiên, bạn không nên sử dụng phương pháp extend
này để thay thế chức năng thuần túy của include
là mixin
các method từ một module vào một class mà nên sử dụng include
vào mục đích này. ^^
Sử dụng extend
để thêm class method vào class
Như đã đề cập ở trên, extend
còn có khả năng thêm các class method từ một module vào một class - điều mà include
không thể làm được.
Hãy xem một ví dụ sau đây:
module Animal
def say_hi
puts "Hi!"
end
end
class Cat
end
Cat.extend Animal
Cat.say_hi
Output:
Hi!
Như vậy ta có thể thấy rằng, bạn có thể extend một instance của một class hoặc extend chính class đó.
Extended
callback
Cũng giống như included
là một callback cho method include
, đây là một callback cho method extend
. Tương tự, nó được gọi mỗi khi một module được extend
vào một module/class khác.
Cùng xem một ví dụ sau đây để hiểu rõ hơn:
module Animal
def self.extended(base)
puts "Class #{base} has been extended with module #{self} !"
end
end
class Cat
extend Animal
end
Output:
Class Cat has been extended with module Animal !
Trên đây mình đã giới thiệu qua về một số kĩ thuật nâng cao khi sử dụng module, hi vọng nó sẽ giúp ích cho bạn đọc trong quá trình làm việc với Ruby (yeah)
Tài liệu tham khảo
All rights reserved