Sự khác biệt giữa một lớp và một mô-đun


437

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 modulevà khi nào bạn sử dụng một, và tại sao sử dụng modulehơn một class?


Câu trả lời:


398

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).


7
Là mô-đun giống như Giao diện trong java?
Saad Rehman Shah

14
@Caffeine không thực sự bởi vì các mô-đun Ruby thực sự bao gồm các triển khai, trong khi các giao diện trong Java là trừu tượng
Jorge Israel Peña

8
Không, các Mô-đun và Gói Java / JAR là những con thú hoàn toàn khác nhau.
Karoly Horvath

9
Tôi giống như các lớp trừu tượng hơn với việc thực hiện phương thức.
Automatico

2
Trên thực tế, @Chole đánh vào một trong những điều hay về mô-đun: Không gian tên. Vì vậy, trong khi module không phải là một tương đương trực tiếp với các gói trong Java, nó có thể được sử dụng để đạt được một cái gì đó tương tự: blog.rubybestpractices.com/posts/gregory/...
michaelok

513
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║               ║ 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)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝

Siêu lớp của lớp 'Class' là gì?
Aashish P

10
Tôi đã nhận được phân cấp, Lớp -> Mô-đun -> Đối tượng -> BasicObject. Mát mẻ!!
Aashish P

Tại sao "mô-đun bao gồm" các biến bỏ qua, khi các lớp và mô-đun đều hỗ trợ các biến lớp? Xem câu trả lời được chấp nhận cho stackoverflow.com/questions/5690458/ từ
kaleidic

Rất nhiều sơ đồ trong tất cả các câu trả lời. Một ví dụ nhỏ đang chạy: rubyfiddle.com/riddles/06081
Donato

16
Làm thế nào một mô-đun "không được khởi tạo" mà vẫn có các phương thức thể hiện?
devius 7/10/2015

91

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ề Mathlớ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()).


11
Nhưng các mô-đun cũng có thể thêm các phương thức cá thể vào lớp bao gồm, trong khi các lớp tĩnh trong Java không thể.
Tái lập lại Monica - notmaynard

4
Tuyên bố này cũng đúng đến từ một nền tảng C # nặng.
Damon Drake

5
Điều này không hoàn toàn đúng; mô-đun không có phương thức tĩnh, chúng chỉ có phương thức. Các mô-đun có thể "tự mở rộng" (cú pháp thực sự extend self), làm cho các phương thức của chúng có sẵn cho selfsiê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 Mathmô-đ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ề selfsiê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.
scottburton11

Tôi muốn nói rằng các mô-đun tương tự như các giao diện với các phương thức trong chúng (các giao diện Java 8 với hàm mặc định) nhưng không thể kế thừa một mô-đun khác với các giao diện java
splitByZero

Làm thế nào câu trả lời này có rất nhiều phiếu bầu? btw đã được nói bằng từ tốt hơn 1mo trước: stackoverflow.com/a/17027346/986862
Andre Figueiredo

39

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.)


Đúng, đây là cách nó hoạt động. Như vậy, các mô-đun không thể so sánh với các lớp "tĩnh" của Java; siêu lớp proxy (một số người gọi nó là "siêu dữ liệu") trở thành người nhận các thông báo gửi phương thức của mô-đun, làm cho có thể so sánh với một lớp tĩnh trong Java và các phương thức của nó hoạt động giống như các phương thức tĩnh. Tuy nhiên, điều tương tự cũng đúng đối với các lớp của Ruby, có thể thực hiện các phương thức giống như "tĩnh" bằng cách nhập extendmộ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.
scottburton11

7

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.


6

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ịch vụ truy cập: sử dụng. toán tử - hằng truy cập: use :: Symbol chỉ câu trả lời này đã đề cập đến điều này!
Qiulang

4

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.


1

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.)


0

Đầ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).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.