ฉันมาจาก Java และตอนนี้ฉันทำงานกับทับทิมได้มากกว่าเดิม
module
คุณลักษณะภาษาหนึ่งที่ผมไม่คุ้นเคยกับการเป็น ฉันกำลังสงสัยว่าmodule
คุณใช้หนึ่งตัวและเมื่อไหร่และทำไมจึงใช้ตัวmodule
ต่อclass
?
ฉันมาจาก Java และตอนนี้ฉันทำงานกับทับทิมได้มากกว่าเดิม
module
คุณลักษณะภาษาหนึ่งที่ผมไม่คุ้นเคยกับการเป็น ฉันกำลังสงสัยว่าmodule
คุณใช้หนึ่งตัวและเมื่อไหร่และทำไมจึงใช้ตัวmodule
ต่อclass
?
คำตอบ:
คำตอบแรกนั้นดีและให้คำตอบเชิงโครงสร้าง แต่อีกแนวทางหนึ่งคือคิดถึงสิ่งที่คุณทำ โมดูลเกี่ยวกับการให้วิธีการที่คุณสามารถใช้ในหลาย ๆ คลาส - คิดว่ามันเป็น "ห้องสมุด" (ดังที่คุณเห็นในแอพ Rails) คลาสเป็นเรื่องเกี่ยวกับวัตถุ โมดูลเกี่ยวกับฟังก์ชั่น
ตัวอย่างเช่นระบบการตรวจสอบและการอนุญาตเป็นตัวอย่างที่ดีของโมดูล ระบบการตรวจสอบความถูกต้องใช้งานได้หลายคลาสในระดับแอพ (ผู้ใช้มีการพิสูจน์ตัวตนเซสชันจัดการการตรวจสอบความถูกต้องคลาสอื่น ๆ จำนวนมากจะทำงานแตกต่างกันไปตามสถานะการรับรองความถูกต้อง) ดังนั้นระบบรับรองความถูกต้อง
คุณอาจใช้โมดูลเมื่อคุณแบ่งปันวิธีการในหลาย ๆ แอพ (อีกครั้งรูปแบบห้องสมุดดีที่นี่)
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║ ║ 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) ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
ฉันประหลาดใจที่ทุกคนไม่ได้พูดเรื่องนี้เลย
เนื่องจากผู้ถามมาจากพื้นหลังของจาวา (และฉันก็ทำเช่นนั้น) นี่คือการเปรียบเทียบที่ช่วยได้
คลาสเหมือนกับคลาส Java
โมดูลเป็นเหมือนคลาส Java คงที่ นึกถึงMath
คลาสใน Java คุณไม่ได้สร้างอินสแตนซ์และคุณใช้วิธีการในคลาสคงที่ (เช่นMath.random()
)
extend self
) ทำให้วิธีการของพวกเขาสามารถใช้ได้กับself
metaclass ของพวกเขา สิ่งนี้ทำให้สามารถส่งวิธีการเช่นเดียวrandom()
กับในMath
โมดูล แต่โดยธรรมชาติแล้ววิธีการของโมดูลนั้นไม่สามารถเรียกด้วยตนเองself
ได้ สิ่งนี้เกี่ยวข้องกับแนวคิดของ Ruby self
, metaclasses และวิธีการค้นหาวิธีการ ลองดู "Metaprogramming Ruby" - Paolo Perlotta สำหรับรายละเอียด
โดยทั่วไปโมดูลจะไม่สามารถสร้างอินสแตนซ์ได้ เมื่อคลาสรวมถึงโมดูลพร็อกซีซูเปอร์คลาสจะถูกสร้างขึ้นที่ให้การเข้าถึงวิธีการโมดูลทั้งหมดรวมถึงวิธีการเรียน
โมดูลสามารถรวมหลายคลาสได้ ไม่สามารถสืบทอดโมดูลได้ แต่โมเดล "mixin" นี้จะให้ประโยชน์ "multiple inheritrance" หลายประเภท ครูสอน OO จะไม่เห็นด้วยกับข้อความนั้น แต่อย่าให้ความบริสุทธิ์เข้าไปในทางที่จะทำให้งานสำเร็จ
(คำตอบนี้เดิมเชื่อมโยงกับhttp://www.rubycentral.com/pickaxe/classes.html
แต่ลิงค์นั้นและโดเมนนั้นไม่ได้ใช้งานอีกต่อไป)
extend
การเรียน Ruby ไม่ได้แยกความแตกต่างระหว่างวิธี "อินสแตนซ์" และ "คลาส / สแตติก" เลยเพียงผู้รับเท่านั้น
Module
ใน Ruby เป็นระดับที่สอดคล้องกับ Java abstract class - มีเมธอดอินสแตนซ์คลาสสามารถสืบทอดจากคลาสนั้น (ผ่านinclude
Ruby guys เรียกมันว่า "mixin") แต่ไม่มีอินสแตนซ์ มีความแตกต่างเล็กน้อยอื่น ๆ แต่ข้อมูลนี้มากพอที่จะให้คุณเริ่มต้น
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)
Bottom line: โมดูลคือการข้ามระหว่างคลาสคงที่ / ยูทิลิตี้และมิกซ์อิน
มิกซ์อินเป็นชิ้นส่วนที่นำกลับมาใช้ใหม่ได้ของการดำเนินการบางส่วนที่สามารถรวมกัน (หรือแต่ง) ในรูปแบบมิกซ์แอนด์แมตช์เพื่อช่วยในการเขียนคลาสใหม่ ชั้นเรียนเหล่านี้สามารถมีสถานะและ / หรือรหัสของตนเองได้แน่นอน
ชั้น
เมื่อคุณกำหนดคลาสคุณจะกำหนดพิมพ์เขียวสำหรับชนิดข้อมูล ข้อมูลเก็บคลาสมีวิธีการโต้ตอบกับข้อมูลนั้นและใช้ในการสร้างอินสแตนซ์ของวัตถุ
โมดูล
โมดูลเป็นวิธีการจัดกลุ่มวิธีการเรียนและค่าคงที่
โมดูลให้ประโยชน์ที่สำคัญสองประการ:
=> โมดูลจัดเตรียมเนมสเปซและป้องกันการปะทะกันของชื่อ Namespace ช่วยหลีกเลี่ยงความขัดแย้งกับฟังก์ชั่นและคลาสที่มีชื่อเดียวกันกับที่คนอื่นเขียน
=> โมดูลใช้สิ่งอำนวยความสะดวกมิกซ์อิน
(รวมถึงโมดูลใน Klazz ให้อินสแตนซ์ของ Klazz เข้าถึงวิธีการของโมดูล)
(ขยาย Klazz ด้วย Mod ให้คลาส Klazz เข้าถึงวิธี Mods)
ครั้งแรกความคล้ายคลึงกันบางอย่างที่ยังไม่ได้กล่าวถึง 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 ของตนเอง (ขยาย)