ความแตกต่างระหว่างคลาสและโมดูล


438

ฉันมาจาก Java และตอนนี้ฉันทำงานกับทับทิมได้มากกว่าเดิม

moduleคุณลักษณะภาษาหนึ่งที่ผมไม่คุ้นเคยกับการเป็น ฉันกำลังสงสัยว่าmoduleคุณใช้หนึ่งตัวและเมื่อไหร่และทำไมจึงใช้ตัวmoduleต่อclass?


คำตอบ:


398

คำตอบแรกนั้นดีและให้คำตอบเชิงโครงสร้าง แต่อีกแนวทางหนึ่งคือคิดถึงสิ่งที่คุณทำ โมดูลเกี่ยวกับการให้วิธีการที่คุณสามารถใช้ในหลาย ๆ คลาส - คิดว่ามันเป็น "ห้องสมุด" (ดังที่คุณเห็นในแอพ Rails) คลาสเป็นเรื่องเกี่ยวกับวัตถุ โมดูลเกี่ยวกับฟังก์ชั่น

ตัวอย่างเช่นระบบการตรวจสอบและการอนุญาตเป็นตัวอย่างที่ดีของโมดูล ระบบการตรวจสอบความถูกต้องใช้งานได้หลายคลาสในระดับแอพ (ผู้ใช้มีการพิสูจน์ตัวตนเซสชันจัดการการตรวจสอบความถูกต้องคลาสอื่น ๆ จำนวนมากจะทำงานแตกต่างกันไปตามสถานะการรับรองความถูกต้อง) ดังนั้นระบบรับรองความถูกต้อง

คุณอาจใช้โมดูลเมื่อคุณแบ่งปันวิธีการในหลาย ๆ แอพ (อีกครั้งรูปแบบห้องสมุดดีที่นี่)


7
โมดูลเหมือนกับส่วนต่อประสานใน java หรือไม่?
ซาดเรห์มานชาห์

14
@ คาเฟอีนไม่ได้เพราะโมดูลทับทิมรวมถึงการใช้งานจริงในขณะที่อินเทอร์เฟซใน Java เป็นนามธรรม
Jorge Israel Peña

8
ไม่โมดูลและแพคเกจ Java / JAR เป็นสัตว์ที่แตกต่างอย่างสิ้นเชิง
Karoly Horvath

9
ฉันเป็นเหมือนคลาสนามธรรมด้วยการใช้วิธีการ
Automatico

2
ที่จริงแล้ว @Chole นิยมหนึ่งในสิ่งที่ดีเกี่ยวกับโมดูล: การตั้งชื่อ ดังนั้นในขณะที่โมดูลไม่ได้เทียบเท่าโดยตรงกับแพคเกจใน Java มันสามารถใช้เพื่อให้บรรลุสิ่งที่คล้ายกัน: 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)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝

ซูเปอร์คลาสของคลาส 'คลาส' คืออะไร
Aashish P

10
ฉันได้รับลำดับชั้น, คลาส -> โมดูล -> วัตถุ -> BasicObject เย็น!!
Aashish P

เหตุใด "โมดูลประกอบด้วย" ละเว้นตัวแปรเมื่อคลาสและโมดูลทั้งคู่สนับสนุนตัวแปรคลาส ดูคำตอบที่ยอมรับสำหรับstackoverflow.com/questions/5690458/…
kaleidic

ไดอะแกรมมากมายในคำตอบเหล่านี้ทั้งหมด ตัวอย่างการใช้งานเล็กน้อย: rubyfiddle.com/riddles/06081
Donato

16
โมดูล "ไม่สามารถสร้างอินสแตนซ์" ได้อย่างไรและยังมีวิธีการอินสแตนซ์?
devius

91

ฉันประหลาดใจที่ทุกคนไม่ได้พูดเรื่องนี้เลย

เนื่องจากผู้ถามมาจากพื้นหลังของจาวา (และฉันก็ทำเช่นนั้น) นี่คือการเปรียบเทียบที่ช่วยได้

คลาสเหมือนกับคลาส Java

โมดูลเป็นเหมือนคลาส Java คงที่ นึกถึงMathคลาสใน Java คุณไม่ได้สร้างอินสแตนซ์และคุณใช้วิธีการในคลาสคงที่ (เช่นMath.random())


11
แต่โมดูลยังสามารถเพิ่มวิธีการอินสแตนซ์ให้กับคลาสที่รวมถึงในขณะที่คลาสคงที่ใน Java ไม่สามารถ
Reinstate Monica - ไม่ใช่ May

4
คำสั่งนี้ยังเป็นจริงมาจากพื้นหลัง C # หนัก
Damon Drake

5
สิ่งนี้ไม่เป็นความจริงทั้งหมด โมดูลไม่มีวิธีการคงที่ แต่ก็มีวิธีการ โมดูลสามารถ "ขยายตัวเอง" (ไวยากรณ์เป็นจริงextend self) ทำให้วิธีการของพวกเขาสามารถใช้ได้กับselfmetaclass ของพวกเขา สิ่งนี้ทำให้สามารถส่งวิธีการเช่นเดียวrandom()กับในMathโมดูล แต่โดยธรรมชาติแล้ววิธีการของโมดูลนั้นไม่สามารถเรียกด้วยตนเองselfได้ สิ่งนี้เกี่ยวข้องกับแนวคิดของ Ruby self, metaclasses และวิธีการค้นหาวิธีการ ลองดู "Metaprogramming Ruby" - Paolo Perlotta สำหรับรายละเอียด
scottburton11

ฉันจะบอกว่าโมดูลคล้ายกับอินเตอร์เฟสที่มีวิธีการในนั้น (Java 8 อินเตอร์เฟสพร้อมปริยายโดยปริยาย) แต่ไม่สามารถสืบทอดจากสิ่งอื่นซึ่งแตกต่างจากอินเตอร์เฟส Java
divideByZero

คำตอบนี้มีคะแนนโหวตเท่าไหร่? btw ที่ถูกกล่าวในคำที่ดีกว่า 1mo ก่อน: stackoverflow.com/a/17027346/986862
Andre Figueiredo

39

โดยทั่วไปโมดูลจะไม่สามารถสร้างอินสแตนซ์ได้ เมื่อคลาสรวมถึงโมดูลพร็อกซีซูเปอร์คลาสจะถูกสร้างขึ้นที่ให้การเข้าถึงวิธีการโมดูลทั้งหมดรวมถึงวิธีการเรียน

โมดูลสามารถรวมหลายคลาสได้ ไม่สามารถสืบทอดโมดูลได้ แต่โมเดล "mixin" นี้จะให้ประโยชน์ "multiple inheritrance" หลายประเภท ครูสอน OO จะไม่เห็นด้วยกับข้อความนั้น แต่อย่าให้ความบริสุทธิ์เข้าไปในทางที่จะทำให้งานสำเร็จ


(คำตอบนี้เดิมเชื่อมโยงกับhttp://www.rubycentral.com/pickaxe/classes.htmlแต่ลิงค์นั้นและโดเมนนั้นไม่ได้ใช้งานอีกต่อไป)


ใช่นี่คือวิธีการทำงาน ดังนั้นโมดูลจึงไม่สามารถเปรียบเทียบได้กับคลาส "สแตติก" ของ Java proxy superclass (บางคนเรียกว่า "metaclass") จะกลายเป็นผู้รับของวิธีการส่งข้อความของโมดูลซึ่งทำให้มันเปรียบได้กับคลาสแบบคงที่ใน Java และวิธีการทำงานเหมือนวิธีแบบคงที่ อย่างไรก็ตามสิ่งเดียวกันนี้เป็นจริงสำหรับคลาสรูบี้ซึ่งสามารถใช้วิธีการแบบ "คงที่" ได้โดยextendการเรียน Ruby ไม่ได้แยกความแตกต่างระหว่างวิธี "อินสแตนซ์" และ "คลาส / สแตติก" เลยเพียงผู้รับเท่านั้น
scottburton11

7

Moduleใน Ruby เป็นระดับที่สอดคล้องกับ Java abstract class - มีเมธอดอินสแตนซ์คลาสสามารถสืบทอดจากคลาสนั้น (ผ่านincludeRuby guys เรียกมันว่า "mixin") แต่ไม่มีอินสแตนซ์ มีความแตกต่างเล็กน้อยอื่น ๆ แต่ข้อมูลนี้มากพอที่จะให้คุณเริ่มต้น


6

namespace: modules เป็น namespaces ... ซึ่งไม่มีอยู่ใน java;)

ฉันเปลี่ยนจาก Java และ python เป็น Ruby ฉันจำได้ว่ามีคำถามเดียวกันนี้ ...

ดังนั้นคำตอบที่ง่ายที่สุดคือโมดูลนั้นเป็นเนมสเปซซึ่งไม่มีอยู่ใน Java ใน java ความคิดที่อยู่ใกล้ namespace เป็นแพคเกจ

ดังนั้นโมดูลในทับทิมจึงเหมือนใน java:
class? ไม่มี
ส่วนต่อประสาน? ไม่มี
คลาสนามธรรม? ไม่มี
แพ็คเกจ? ใช่อาจจะ)

วิธีการคงที่ภายในชั้นเรียนใน java: เช่นเดียวกับวิธีการภายในโมดูลในทับทิม

ในจาวาหน่วยขั้นต่ำคือคลาสคุณไม่สามารถใช้ฟังก์ชันนอกคลาสได้ อย่างไรก็ตามในทับทิมนี่เป็นไปได้ (เช่นหลาม)

แล้วอะไรคือโมดูล?
ชั้นเรียนวิธีการค่าคงที่ โมดูลปกป้องพวกเขาภายใต้เนมสเปซนั้น

ไม่มีอินสแตนซ์:ไม่สามารถใช้โมดูลเพื่อสร้างอินสแตนซ์

Mixed ins:บางครั้งรูปแบบการสืบทอดไม่ดีสำหรับคลาส แต่ในแง่ของการทำงานต้องการจัดกลุ่มชุดของคลาส / วิธีการ / ค่าคงที่ด้วยกัน

กฎเกี่ยวกับโมดูลใน ruby:
- ชื่อโมดูลคือ UpperCamelCase
- ค่าคงที่ภายในโมดูลคือ ALL CAPS (กฎนี้เหมือนกันสำหรับค่าคงที่ ruby ​​ทั้งหมดไม่ใช่เฉพาะโมดูล)
- วิธีการเข้าถึง: ใช้ ตัวดำเนินการ
- ค่าคงที่เข้าถึง: ใช้สัญลักษณ์ ::

ตัวอย่างง่ายๆของโมดูล:

module MySampleModule
  CONST1 = "some constant"

  def self.method_one(arg1)
    arg1 + 2
  end
end

วิธีการใช้วิธีการภายในโมดูล:

puts MySampleModule.method_one(1) # prints: 3

วิธีใช้ค่าคงที่ของโมดูล:

puts MySampleModule::CONST1 # prints: some constant

ข้อตกลงอื่น ๆ เกี่ยวกับโมดูล:
ใช้หนึ่งโมดูลในไฟล์ (เช่นคลาส ruby, หนึ่งคลาสต่อไฟล์ ruby)


“ - วิธีการเข้าถึง: ใช้ ผู้ประกอบการ - การเข้าถึงค่าคงที่: ใช้ :: สัญลักษณ์” เท่านั้นคำตอบนี้กล่าวถึงนี้!
Qiulang

4

Bottom line: โมดูลคือการข้ามระหว่างคลาสคงที่ / ยูทิลิตี้และมิกซ์อิน

มิกซ์อินเป็นชิ้นส่วนที่นำกลับมาใช้ใหม่ได้ของการดำเนินการบางส่วนที่สามารถรวมกัน (หรือแต่ง) ในรูปแบบมิกซ์แอนด์แมตช์เพื่อช่วยในการเขียนคลาสใหม่ ชั้นเรียนเหล่านี้สามารถมีสถานะและ / หรือรหัสของตนเองได้แน่นอน


1

ชั้น

เมื่อคุณกำหนดคลาสคุณจะกำหนดพิมพ์เขียวสำหรับชนิดข้อมูล ข้อมูลเก็บคลาสมีวิธีการโต้ตอบกับข้อมูลนั้นและใช้ในการสร้างอินสแตนซ์ของวัตถุ

โมดูล

  • โมดูลเป็นวิธีการจัดกลุ่มวิธีการเรียนและค่าคงที่

  • โมดูลให้ประโยชน์ที่สำคัญสองประการ:

    => โมดูลจัดเตรียมเนมสเปซและป้องกันการปะทะกันของชื่อ Namespace ช่วยหลีกเลี่ยงความขัดแย้งกับฟังก์ชั่นและคลาสที่มีชื่อเดียวกันกับที่คนอื่นเขียน

    => โมดูลใช้สิ่งอำนวยความสะดวกมิกซ์อิน

(รวมถึงโมดูลใน Klazz ให้อินสแตนซ์ของ Klazz เข้าถึงวิธีการของโมดูล)

(ขยาย Klazz ด้วย Mod ให้คลาส Klazz เข้าถึงวิธี Mods)


0

ครั้งแรกความคล้ายคลึงกันบางอย่างที่ยังไม่ได้กล่าวถึง Ruby รองรับคลาสที่เปิดอยู่ แต่โมดูลก็เปิดเหมือนกัน ท้ายที่สุดคลาสสืบทอดจากโมดูลในห่วงโซ่การสืบทอดคลาสดังนั้นคลาสและโมดูลจะมีลักษณะการทำงานที่คล้ายกัน

แต่คุณต้องถามตัวเองว่าอะไรคือจุดประสงค์ของการมีทั้ง Class และ Module ในภาษาการเขียนโปรแกรม คลาสมีวัตถุประสงค์เพื่อเป็นพิมพ์เขียวสำหรับสร้างอินสแตนซ์และแต่ละอินสแตนซ์เป็นรูปแบบที่รับรู้ของพิมพ์เขียว อินสแตนซ์เป็นเพียงการเปลี่ยนแปลงที่แท้จริงของพิมพ์เขียว (คลาส) โดยปกติคลาสจะทำหน้าที่สร้างวัตถุ นอกจากนี้เนื่องจากบางครั้งเราต้องการพิมพ์เขียวหนึ่งชิ้นเพื่อให้ได้มาจากพิมพ์เขียวอื่นคลาสจึงได้รับการออกแบบมาเพื่อรองรับการสืบทอด

โมดูลไม่สามารถสร้างอินสแตนซ์ไม่สร้างวัตถุและไม่สนับสนุนการสืบทอด ดังนั้นโปรดจำไว้ว่าโมดูลหนึ่งไม่ได้สืบทอดจากโมดูลอื่น!

ดังนั้นสิ่งที่เป็นจุดของการมีโมดูลในภาษา? การใช้โมดูลอย่างชัดเจนอย่างหนึ่งคือการสร้างเนมสเปซและคุณจะสังเกตเห็นสิ่งนี้ด้วยภาษาอื่นเช่นกัน สิ่งที่ยอดเยี่ยมเกี่ยวกับ Ruby ก็คือโมดูลสามารถเปิดใหม่ได้ (เช่นเดียวกับคลาส) และนี่เป็นการใช้งานครั้งใหญ่เมื่อคุณต้องการใช้ namespace ในไฟล์ Ruby ที่แตกต่างกัน:

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

แต่ไม่มีการสืบทอดระหว่างโมดูล:

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>

โมดูล Apple ไม่ได้สืบทอดวิธีการใด ๆ จากโมดูล Green และเมื่อเรารวม Apple ในคลาส Fruit วิธีการของโมดูล Apple จะถูกเพิ่มลงในโซ่บรรพบุรุษของอินสแตนซ์ของ Apple แต่ไม่ใช่วิธีของโมดูล Green แม้ว่า Green โมดูลถูกกำหนดในโมดูล Apple

ดังนั้นเราจะเข้าถึงวิธีสีเขียวได้อย่างไร คุณต้องรวมไว้ในชั้นเรียนของคุณอย่างชัดเจน:

class Fruit
  include Apple::Green
end
 => Fruit 
 > f.green
=> green

แต่ Ruby มีการใช้งานที่สำคัญอีกอย่างสำหรับ Modules นี่คือสิ่งอำนวยความสะดวก Mixin ที่ฉันอธิบายในคำตอบอื่นใน SO แต่เพื่อสรุป mixins ช่วยให้คุณสามารถกำหนดวิธีการในห่วงโซ่การสืบทอดของวัตถุ ผ่าน mixins คุณสามารถเพิ่มวิธีการในห่วงโซ่การสืบทอดของอินสแตนซ์ของวัตถุ (รวม) หรือ singleton_class ของตนเอง (ขยาย)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.