Tôi đến từ Java và bây giờ tôi đang làm việc nhiều hơn với Ruby.
Một tính năng ngôn ngữ tôi không quen thuộc là module
. Tôi tự hỏi chính xác những gì là một module
và khi nào bạn sử dụng một, và tại sao sử dụng module
hơn một class
?
Tôi đến từ Java và bây giờ tôi đang làm việc nhiều hơn với Ruby.
Một tính năng ngôn ngữ tôi không quen thuộc là module
. Tôi tự hỏi chính xác những gì là một module
và khi nào bạn sử dụng một, và tại sao sử dụng module
hơn một class
?
Câu trả lời:
Câu trả lời đầu tiên là tốt và đưa ra một số câu trả lời có cấu trúc, nhưng cách tiếp cận khác là suy nghĩ về những gì bạn đang làm. Các mô-đun là về việc cung cấp các phương thức mà bạn có thể sử dụng trên nhiều lớp - hãy nghĩ về chúng như là "thư viện" (như bạn thấy trong ứng dụng Rails). Các lớp học là về các đối tượng; mô-đun là về chức năng.
Ví dụ, hệ thống xác thực và ủy quyền là những ví dụ tốt về các mô-đun. Hệ thống xác thực hoạt động trên nhiều lớp cấp ứng dụng (người dùng được xác thực, phiên quản lý xác thực, rất nhiều lớp khác sẽ hoạt động khác nhau dựa trên trạng thái xác thực), vì vậy hệ thống xác thực hoạt động như API chia sẻ.
Bạn cũng có thể sử dụng một mô-đun khi bạn có các phương pháp chia sẻ trên nhiều ứng dụng (một lần nữa, mô hình thư viện rất tốt ở đây).
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║ ║ class ║ module ║
╠═══════════════╬═══════════════════════════╬═════════════════════════════════╣
║ instantiation ║ can be instantiated ║ can *not* be instantiated ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ usage ║ object creation ║ mixin facility. provide ║
║ ║ ║ a namespace. ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ superclass ║ module ║ object ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ methods ║ class methods and ║ module methods and ║
║ ║ instance methods ║ instance methods ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inheritance ║ inherits behaviour and can║ No inheritance ║
║ ║ be base for inheritance ║ ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inclusion ║ cannot be included ║ can be included in classes and ║
║ ║ ║ modules by using the include ║
║ ║ ║ command (includes all ║
║ ║ ║ instance methods as instance ║
║ ║ ║ methods in a class/module) ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ extension ║ can not extend with ║ module can extend instance by ║
║ ║ extend command ║ using extend command (extends ║
║ ║ (only with inheritance) ║ given instance with singleton ║
║ ║ ║ methods from module) ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
Tôi ngạc nhiên khi không ai nói điều này.
Vì người hỏi đến từ một nền tảng Java (và tôi cũng vậy), đây là một sự tương tự có ích.
Các lớp đơn giản giống như các lớp Java.
Các mô-đun giống như các lớp tĩnh Java. Hãy suy nghĩ về Math
lớp học trong Java. Bạn không khởi tạo nó và bạn sử dụng lại các phương thức trong lớp tĩnh (ví dụ. Math.random()
).
extend self
), làm cho các phương thức của chúng có sẵn cho self
siêu dữ liệu của chúng. Điều này làm cho nó có thể gửi một phương thức như random()
trên một Math
mô-đun. Nhưng theo bản chất của chúng, các phương thức của mô-đun không thể được gọi theo cách riêng của mô-đun self
. Điều này có liên quan đến khái niệm của Ruby về self
siêu dữ liệu của nó và cách thức tra cứu phương thức hoạt động. Kiểm tra "Metaprogramming Ruby" - Paolo Perlotta để biết chi tiết.
Về cơ bản, mô-đun không thể được khởi tạo. Khi một lớp bao gồm một mô-đun, một siêu lớp proxy được tạo ra cung cấp quyền truy cập vào tất cả các phương thức mô-đun cũng như các phương thức lớp.
Một mô-đun có thể được bao gồm bởi nhiều lớp. Các mô-đun không thể được kế thừa, nhưng mô hình "mixin" này cung cấp một loại "thừa kế" hữu ích. Những người theo chủ nghĩa thuần túy sẽ không đồng ý với tuyên bố đó, nhưng đừng để sự thuần khiết cản trở công việc được hoàn thành.
(Câu trả lời này ban đầu được liên kết đến http://www.rubycentral.com/pickaxe/classes.html
, nhưng liên kết đó và tên miền của nó không còn hoạt động.)
extend
một lớp. Ruby hoàn toàn không phân biệt giữa các phương thức "thể hiện" và "lớp / tĩnh", chỉ có các máy thu của chúng.
Module
ở Ruby, ở một mức độ nào đó, tương ứng với lớp trừu tượng Java - có các phương thức cá thể, các lớp có thể kế thừa từ nó (thông qua include
, các chàng trai Ruby gọi nó là "mixin"), nhưng không có trường hợp nào. Có những khác biệt nhỏ khác, nhưng nhiều thông tin này là đủ để bạn bắt đầu.
không gian tên: mô-đun là không gian tên ... không tồn tại trong java;)
Tôi cũng đã chuyển từ Java và python sang Ruby, tôi nhớ có chính xác câu hỏi này ...
Vì vậy, câu trả lời đơn giản nhất là mô-đun là một không gian tên, không tồn tại trong Java. Trong java, tư duy gần nhất với không gian tên là một gói .
Vì vậy, một mô-đun trong ruby giống như những gì trong java:
class? Không có
giao diện? Không có
lớp trừu tượng? Không có
gói? Có lẽ)
Các phương thức tĩnh bên trong các lớp trong java: giống như các phương thức bên trong các mô đun trong ruby
Trong java, đơn vị tối thiểu là một lớp, bạn không thể có chức năng bên ngoài một lớp. Tuy nhiên trong ruby điều này là có thể (như trăn).
Vì vậy, những gì đi vào một mô-đun?
các lớp, phương thức, hằng số. Module bảo vệ chúng dưới không gian tên đó.
Không có phiên bản: mô-đun không thể được sử dụng để tạo phiên bản
Hỗn hợp: đôi khi các mô hình thừa kế không tốt cho các lớp, nhưng về mặt chức năng muốn nhóm một nhóm các lớp / phương thức / hằng với nhau
Quy tắc về các mô-đun trong ruby:
- Tên mô-đun là UpperCamelCase
- hằng số trong các mô-đun là TẤT CẢ CAPS (quy tắc này giống nhau cho tất cả các hằng số ruby, không dành riêng cho mô-đun)
- phương thức truy cập: sử dụng. toán tử
- hằng truy cập: use :: kí hiệu
ví dụ đơn giản về một mô-đun:
module MySampleModule
CONST1 = "some constant"
def self.method_one(arg1)
arg1 + 2
end
end
Cách sử dụng các phương thức bên trong một mô-đun:
puts MySampleModule.method_one(1) # prints: 3
Làm thế nào để sử dụng hằng số của một mô-đun:
puts MySampleModule::CONST1 # prints: some constant
Một số quy ước khác về các mô-đun:
Sử dụng một mô-đun trong một tệp (như các lớp ruby, một lớp cho mỗi tệp ruby)
Dòng dưới cùng: Một mô-đun là một giao thoa giữa một lớp tĩnh / tiện ích và một mixin.
Mixins là những phần có thể tái sử dụng của việc thực hiện "một phần", có thể được kết hợp (hoặc sáng tác) theo kiểu kết hợp và kết hợp, để giúp viết các lớp mới. Tất nhiên, các lớp này có thể có trạng thái và / hoặc mã riêng.
Lớp học
Khi bạn xác định một lớp, bạn xác định một kế hoạch chi tiết cho một kiểu dữ liệu. lớp giữ dữ liệu, có phương thức tương tác với dữ liệu đó và được sử dụng để khởi tạo các đối tượng.
Mô-đun
Các mô-đun là một cách để nhóm các phương thức, lớp và hằng số lại với nhau.
Các mô-đun cung cấp cho bạn hai lợi ích chính:
=> Các mô-đun cung cấp một không gian tên và ngăn ngừa xung đột tên. Không gian tên giúp tránh xung đột với các chức năng và các lớp có cùng tên đã được viết bởi người khác.
=> Các mô-đun thực hiện cơ sở mixin.
(bao gồm Mô-đun trong Klazz cung cấp cho các phiên bản của Klazz quyền truy cập vào các phương thức Mô-đun.)
(mở rộng Klazz với Mod cho phép lớp Klazz truy cập vào các phương thức Mod.)
Đầu tiên, một số điểm tương đồng chưa được đề cập. Ruby hỗ trợ các lớp mở, nhưng các mô-đun cũng mở. Xét cho cùng, Class kế thừa từ Module trong chuỗi kế thừa Class và do đó Class và Module có một số hành vi tương tự.
Nhưng bạn cần tự hỏi mục đích của việc có cả Lớp và Mô-đun trong ngôn ngữ lập trình là gì? Một lớp được dự định là một kế hoạch chi tiết để tạo các thể hiện và mỗi thể hiện là một biến thể nhận ra của kế hoạch chi tiết. Một thể hiện chỉ là một biến thể nhận ra của một kế hoạch chi tiết (Lớp). Đương nhiên, Classes có chức năng tạo đối tượng. Hơn nữa, vì đôi khi chúng ta muốn một bản thiết kế xuất phát từ một bản thiết kế khác, các Lớp được thiết kế để hỗ trợ kế thừa.
Các mô-đun không thể được khởi tạo, không tạo đối tượng và không hỗ trợ kế thừa. Vì vậy, hãy nhớ một mô-đun KHÔNG kế thừa từ một mô-đun khác!
Vì vậy, điểm có các Mô-đun trong một ngôn ngữ là gì? Một cách sử dụng Mô-đun rõ ràng là tạo một không gian tên và bạn cũng sẽ nhận thấy điều này với các ngôn ngữ khác. Một lần nữa, điều thú vị về Ruby là các Mô-đun có thể được mở lại (giống như các Lớp học). Và đây là một cách sử dụng lớn khi bạn muốn sử dụng lại một không gian tên trong các tệp Ruby khác nhau:
module Apple
def a
puts 'a'
end
end
module Apple
def b
puts 'b'
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c527c98>
> f.a
=> a
> f.b
=> b
Nhưng không có sự kế thừa giữa các mô-đun:
module Apple
module Green
def green
puts 'green'
end
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c462420>
> f.green
NoMethodError: undefined method `green' for #<Fruit:0x007fe90c462420>
Mô-đun Apple không kế thừa bất kỳ phương thức nào từ mô-đun Xanh và khi chúng tôi đưa Apple vào lớp Fruit, các phương thức của mô-đun Apple được thêm vào chuỗi tổ tiên của các phiên bản Apple, nhưng không phải là phương thức của mô-đun Xanh, mặc dù là Xanh mô-đun đã được xác định trong mô-đun Apple.
Vậy làm thế nào để chúng ta có được quyền truy cập vào phương thức xanh? Bạn phải bao gồm nó một cách rõ ràng trong lớp của bạn:
class Fruit
include Apple::Green
end
=> Fruit
> f.green
=> green
Nhưng Ruby có một cách sử dụng quan trọng khác cho các Mô-đun. Đây là cơ sở Mixin, mà tôi mô tả trong một câu trả lời khác về SO. Nhưng để tóm tắt, mixins cho phép bạn xác định các phương thức vào chuỗi kế thừa của các đối tượng. Thông qua mixins, bạn có thể thêm các phương thức vào chuỗi kế thừa của các thể hiện đối tượng (bao gồm) hoặc singleton_ class của bản thân (mở rộng).