Najlepszym sposobem, w jaki rozumiem, że mixiny są wirtualne klasy. Miksery to „klasy wirtualne”, które zostały wprowadzone do łańcucha przodków klasy lub modułu.
Kiedy używamy „włączania” i przekazujemy mu moduł, dodaje on moduł do łańcucha nadrzędnego bezpośrednio przed klasą, z której dziedziczimy:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Każdy obiekt w Rubim ma również klasę pojedynczą. Metody dodane do tej klasy pojedynczej mogą być wywoływane bezpośrednio w obiekcie, a więc działają jako metody „klasowe”. Kiedy używamy "rozszerzania" na obiekcie i przekazujemy obiektowi moduł, dodajemy metody modułu do pojedynczej klasy obiektu:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Możemy uzyskać dostęp do klasy singleton za pomocą metody singleton_class:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby udostępnia kilka punktów zaczepienia dla modułów, gdy są one mieszane w klasy / moduły. included
jest metodą przechwytującą dostarczaną przez Rubiego, która jest wywoływana za każdym razem, gdy włączysz moduł do jakiegoś modułu lub klasy. Podobnie jak w zestawie, jest powiązany extended
hak do rozszerzenia. Zostanie wywołany, gdy moduł zostanie rozszerzony o inny moduł lub klasę.
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
Tworzy to interesujący wzorzec, którego mogą użyć programiści:
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
Jak widać, ten pojedynczy moduł dodaje metody instancji, metody „klasy” i działa bezpośrednio na klasę docelową (w tym przypadku wywołanie metody a_class_method ()).
ActiveSupport :: Concern hermetyzuje ten wzorzec. Oto ten sam moduł przepisany do korzystania z ActiveSupport :: Concern:
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