- Bài viết được dịch từ bài Is module_function really the same as extend self?.
- apidock 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_function
vàextend self
module_function
vsextend 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_function
và extend 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
:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">module</span> <span class="token constant">RubyCademy</span> <span class="token keyword">extend</span> <span class="token keyword">self</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">headline</span></span> puts <span class="token string">"Learn Ruby and Ruby on Rails!"</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">RubyCademy</span><span class="token punctuation">.</span>headline <span class="token comment"># => Learn Ruby and Ruby on Rails!</span> |
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:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">module</span> <span class="token constant">RubyCademy</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">headline</span></span> puts <span class="token string">"Learn Ruby and Ruby on Rails!"</span> <span class="token keyword">end</span> module_function <span class="token symbol">:headline</span> <span class="token keyword">end</span> <span class="token constant">RubyCademy</span><span class="token punctuation">.</span>headline <span class="token comment"># => Learn Ruby and Ruby on Rails!</span> |
Ở đâ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 self
và module_ 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">module</span> <span class="token constant">TheDevelopersJourney</span> <span class="token keyword">extend</span> <span class="token keyword">self</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">headline</span></span> puts <span class="token string">"Thoughts about the life of a developer.."</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">class</span> <span class="token class-name">MediumBlog</span> <span class="token keyword">include</span> <span class="token constant">TheDevelopersJourney</span> <span class="token keyword">end</span> <span class="token constant">TheDevelopersJourney</span><span class="token punctuation">.</span>singleton_methods<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token operator">?</span><span class="token punctuation">(</span><span class="token symbol">:headline</span><span class="token punctuation">)</span> <span class="token comment"># => true</span> <span class="token constant">MediumBlog</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">.</span>public_methods<span class="token punctuation">.</span><span class="token keyword">include</span><span class="token operator">?</span><span class="token punctuation">(</span><span class="token symbol">:headline</span><span class="token punctuation">)</span> <span class="token comment"># => true</span> |
Đầ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 ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">module</span> <span class="token constant">ModuleFunction</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">who_am_i</span></span> <span class="token string">"ModuleFunction"</span> <span class="token keyword">end</span> module_function <span class="token symbol">:who_am_i</span> <span class="token keyword">end</span> <span class="token constant">ModuleFunction</span><span class="token punctuation">.</span>who_am_i <span class="token comment"># => "ModuleFunction"</span> <span class="token keyword">module</span> <span class="token constant">ModuleFunction</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">who_am_i</span></span> <span class="token string">"overriden ModuleFunction"</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">ModuleFunction</span><span class="token punctuation">.</span>who_am_i <span class="token comment"># => "ModuleFunction"</span> <span class="token keyword">module</span> <span class="token constant">ModuleFunction</span> module_function <span class="token symbol">:who_am_i</span> <span class="token keyword">end</span> <span class="token constant">ModuleFunction</span><span class="token punctuation">.</span>who_am_i <span class="token comment"># => "overriden ModuleFunction"****</span> |
- Đầ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 đè
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">module</span> <span class="token constant">ModuleFunction</span> <span class="token keyword">extend</span> <span class="token keyword">self</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">who_am_i</span></span> <span class="token string">"ModuleFunction"</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">ModuleFunction</span><span class="token punctuation">.</span>who_am_i <span class="token comment"># => "ModuleFunction"</span> <span class="token keyword">module</span> <span class="token constant">ModuleFunction</span> <span class="token keyword">def</span> <span class="token method-definition"><span class="token function">who_am_i</span></span> <span class="token string">"overridden ModuleFunction"</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">ModuleFunction</span><span class="token punctuation">.</span>who_am_i <span class="token comment"># => "overridden ModuleFunction"</span> |
=> 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_function được ứng dụng rất mạnh trong các Thư viện Chuẩn Ruby.