Đặc trưng của module_function vs extend self trong ruby



Trong bài viết này, chúng ta sẽ khám phá các chủ đề sau:

  • Phân biệt giữa module_functionextend self
  • module_function vs extend self

Nếu như bạn không quen thuộc với khái niệm cơ bản module trong Ruby: đọc Module in Ruby Part I


Giới thiệu

Trong Ruby, một module có thể được sử dụng như một instance logic. Nó nhóm các phương thức ở mức mô-đun lại, mà không sử dụng dựa trên cơ sở mixin - ví dụ: module Base64.

Trong Ruby, có một tập hợp các kỹ thuật để đạt được kết quả mong đợi này. 2 cái được biết đến nhiều nhất là module module_functionextend self.

Hoạt động

Chi tiết sự khác biệt chính giữa 2 cách tiếp cận này là gì?

extend self:

module RubyCademy
  extend self

  def headline
    puts "Learn Ruby and Ruby on Rails!"
  end
end

RubyCademy.headline # => Learn Ruby and Ruby on Rails!

Bằng cách extend self trong module RubyCademy, tất cả các instance methods được xác định trong module này sẽ có sẵn ở module level - Đó là lý do tại sao chúng ta có thể gọi RubyCademy.headline.

module_function:

module RubyCademy
  def headline
    puts "Learn Ruby and Ruby on Rails!"
  end
  
  module_function :headline
end

RubyCademy.headline # => Learn Ruby and Ruby on Rails!

Ở đây, chúng ta cũng định nghĩa một instance method RubyCademy#headline. Sau đó, chúng ta gọi module_function :headline. Tại thời điểm này, phương thức headline cũng có sẵn dưới dạng module method - còn được gọi là module function.


extend self vs module_function

Cho đến thời điểm hiện tại, chúng ta đã thấy có 2 cách để khai báo các instance method là module method: extend selfmodule_ function. Vì vậy, hãy xem điều gì xảy ra ở sâu bên trong để thực sự hiểu sự khác biệt của chúng.


Hiển thị method

module TheDevelopersJourney
  extend self

  def headline
    puts "Thoughts about the life of a developer.."
  end
end

class MediumBlog
  include TheDevelopersJourney
end

TheDevelopersJourney.singleton_methods.include?(:headline) # => true
MediumBlog.new.public_methods.include?(:headline)          # => true

Đầu tiên, chúng ta xác định một module TheDevelopersJourney có chứa một instance method headline. Sau đó, chúng ta tạo một module function headline bằng cách sử dụng cơ chế extend self. Tiếp theo, chúng ta xác định một class MediumBlog, thêm include TheDevelopersJourney . Cuối cùng, chúng ta nhận thấy rằng việc gọi extend self đã phần nào thay đổi loại phương thức:

  • một cái headline singleton method đã được thêm vào module TheDevelopersJourney
  • cái headline được included vào MediumBlog là public method

Còn bây giờ module_function thì sao ?

module RubyCademy
  def headline
    puts "Learn Ruby and Ruby on Rails!"
  end

  module_function :headline
end

class Website
  include RubyCademy
end

RubyCademy.singleton_methods.include?(:headline) # => true
Website.new.private_methods.include?(:headline)  # => true

Đầu tiên, chúng ta xác định một module RubyCademy có chứa một phương thức instance headline. Sau đó, chúng ta tạo ra một module method headline bằng cách sử dụng quy trình module_function. Tiếp theo, chúng ta xác định một class Website bao gồm module RubyCademy. Cuối cùng, chúng ta nhận thấy rằng lệnh gọi tới module_ functions đã thay đổi một phần kiểu phương thức:

  • một cái headline singleton method đã được thêm vào module RubyCademy
  • cái headline được included là private method

Đây là sự khác biệt chính giữa extend self và module_function. Cái sau(module_function) thực sự tạo ra một module function bằng cách hạn chế quyền truy cập vào phương thức được include trong khi extend self vẫn cho phép truy cập vào phương thức được include.


module function copy Một sự khác biệt khác vẫn là sự thật rằng việc extend self và module_ function không generate ra cùng một loại module function

module ModuleFunction
  def who_am_i
    "ModuleFunction"
  end

  module_function :who_am_i
end

ModuleFunction.who_am_i # => "ModuleFunction"

module ModuleFunction
  def who_am_i
    "overriden ModuleFunction"
  end
end

ModuleFunction.who_am_i # => "ModuleFunction"

module ModuleFunction
  module_function :who_am_i
end

ModuleFunction.who_am_i # => "overriden ModuleFunction"****
  • Đầu tiên, chúng ta xác định phương thức: who_am_i là hàm mô-đun bằng cách sử dụng module_function :who_am_i.
  • Sau đó, chúng ta ghi đè phương thức này nhưng chúng ta nhận thấy rằng sửa đổi không được áp dụng.
  • Cuối cùng, để áp dụng được sửa đổi mong muốn, chúng ta phải gọi lại module_ function: who_am_i.

Thật vậy, vì module function của chúng ta là bản sao của phương thức instance who_am_i ban đầu, việc sửa đổi của chúng tôi đối với phương thức phiên bản này đương nhiên không được truyền sang module function - trừ khi chúng tôi khai báo lại(copy lại) phương thức instance đã sửa đổi dưới dạng m,odule function bằng cách sử dụng module_ function.

Đừng để xem cách thức extend self hoạt động với instance method bị ghi đè

module ModuleFunction
  extend self

  def who_am_i
    "ModuleFunction"
  end
end

ModuleFunction.who_am_i # => "ModuleFunction"

module ModuleFunction
  def who_am_i
    "overridden ModuleFunction"
  end
end

ModuleFunction.who_am_i # => "overridden ModuleFunction"

=> một khi đã extend self => tất cả instance method khai báo tiếp theo sau, hay là bị ghi đè: đều sẽ trở thành method câp độ module của ModuleFunction

Thật vậy, vì module function của chúng ta không phải là bản copy của phương thức instance who_am_i ban đầu, việc sửa đổi của chúng ta đối với phương thức instance được truyền một cách hiển nhiên đến module function.


Ưu điểm

extend self:

  • không cần copy method, => meta programming thoải mái

module_function:

  • Dễ đọc
  • khả năng: Đặt các phương thức được include ở chế độ private là điều kiện tiên quyết của thiết kế module function (nếu muốn).
  • sao chép Module function: cơ chế an toàn để tránh ghi đè chức năng mô-đun giúp ngăn ngừa các tác dụng phụ.

kết luận

Bây giờ bạn có các quan điểm để đưa ra quyết định đúng đắn khi nói đến việc tạo một module function ... dùng hay không dùng . 😊

Cuối cùng, thật thú vị khi sử dụng phương pháp này khi các method của bạn độc lập với các đối tượng bên trong - Ví dụ: mô-đun Math. Lưu ý rằng module_funciton được ứng dụng rất mạnh trong các Thư viện Chuẩn Ruby.


All Rights Reserved