12/08/2018, 13:03

Advanced Modules in Ruby

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 mixindễ 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, ...

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 mixindễ 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)

0