Cách tốt nhất tôi hiểu mixins là các lớp ảo. Mixins là "các lớp ảo" đã được đưa vào chuỗi tổ tiên của một lớp hoặc mô-đun.
Khi chúng ta sử dụng "bao gồm" và truyền cho nó một mô-đun, nó sẽ thêm mô-đun vào chuỗi tổ tiên ngay trước lớp mà chúng ta đang kế thừa từ:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Mọi đối tượng trong Ruby cũng có một lớp đơn. Các phương thức được thêm vào lớp singleton này có thể được gọi trực tiếp trên đối tượng và do đó chúng hoạt động như các phương thức "lớp". Khi chúng ta sử dụng "mở rộng" trên một đối tượng và truyền cho đối tượng một mô-đun, chúng ta sẽ thêm các phương thức của mô-đun vào lớp singleton của đối tượng:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Chúng ta có thể truy cập lớp singleton bằng phương thức singleton_group:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby cung cấp một số hook cho các mô-đun khi chúng được trộn vào các lớp / mô-đun. included
là một phương thức hook được cung cấp bởi Ruby, được gọi bất cứ khi nào bạn đưa mô-đun vào một số mô-đun hoặc lớp. Cũng giống như bao gồm, có một extended
cái móc liên quan để mở rộng. Nó sẽ được gọi khi một mô-đun được mở rộng bởi một mô-đun hoặc lớp khác.
module M
def self.included(target)
puts "included into #{target}"
end
def self.extended(target)
puts "extended into #{target}"
end
end
class MyClass
include M
end
class MyClass2
extend M
end
Điều này tạo ra một mô hình thú vị mà các nhà phát triển có thể sử dụng:
module M
def self.included(target)
target.send(:include, InstanceMethods)
target.extend ClassMethods
target.class_eval do
a_class_method
end
end
module InstanceMethods
def an_instance_method
end
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
class MyClass
include M
# a_class_method called
end
Như bạn có thể thấy, mô-đun đơn này đang thêm các phương thức cá thể, phương thức "lớp" và hoạt động trực tiếp trên lớp đích (gọi a_group_method () trong trường hợp này).
ActiveSupport :: Mối quan tâm gói gọn mẫu này. Đây là cùng một mô-đun được viết lại để sử dụng ActiveSupport :: Mối quan tâm:
module M
extend ActiveSupport::Concern
included do
a_class_method
end
def an_instance_method
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end