เหตุใด Clojure จึงมี 5 วิธีในการกำหนดคลาสแทนที่จะเป็นเพียงวิธีเดียว


84

Clojure มี gen-class, reify, proxy และยังมี deftype และ defrecord เพื่อกำหนดประเภทข้อมูลที่เหมือนคลาสใหม่ สำหรับภาษาที่ให้ความสำคัญกับความเรียบง่ายทางวากยสัมพันธ์และหลีกเลี่ยงความซับซ้อนที่ไม่จำเป็นดูเหมือนว่าจะเป็นความคลาด ใครช่วยอธิบายได้ว่าทำไมถึงเป็นเช่นนั้น? Defclass สไตล์ Lisp ทั่วไปจะเพียงพอหรือไม่?

คำตอบ:


91

นี่คือการผสมผสานของปัจจัยสามอย่างที่แตกต่างกัน:

  1. ระบบประเภทเฉพาะของ jvm
  2. ความต้องการความหมายที่แตกต่างกันเล็กน้อยสำหรับกรณีการใช้งานที่แตกต่างกันเมื่อกำหนดประเภท
  3. ความจริงที่ว่าบางส่วนได้รับการพัฒนามาก่อนหน้านี้และบางส่วนในภายหลังเนื่องจากภาษาได้พัฒนาไป

ก่อนอื่นเรามาพิจารณาว่าสิ่งเหล่านี้ทำอะไร deftypeและgen-classมีความคล้ายคลึงกันตรงที่ทั้งคู่กำหนดคลาสที่มีชื่อสำหรับการคอมไพล์ล่วงหน้า Gen-class มาก่อนตามด้วย deftype ใน clojure 1.2 Deftype เป็นที่ต้องการและมีลักษณะการทำงานที่ดีกว่า แต่มีข้อ จำกัด มากกว่า คลาส deftype สามารถสอดคล้องกับอินเทอร์เฟซ แต่ไม่สามารถสืบทอดจากคลาสอื่นได้

Reifyและproxyถูกใช้เพื่อสร้างอินสแตนซ์ของคลาสที่ไม่ระบุชื่อแบบไดนามิกที่รันไทม์ Proxy มาก่อน reify มาพร้อมกับ deftype และ defrecord ใน clojure 1.2 Reify เป็นที่ต้องการเช่นเดียวกับ deftype โดยที่ความหมายไม่ จำกัด เกินไป

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

สำหรับการอ่านเพิ่มเติมโปรดดู:

หน้าประเภทข้อมูล clojure.org

เธรดกลุ่ม Google ที่มีการแนะนำ deftype และ reify


1
เธรดกลุ่มของ Google มีค่ามาก ความเข้าใจของฉันมีไว้สำหรับพร็อกซี java-interop gen-class จะถูกแทนที่ด้วย reify และ deftype เป็นส่วนใหญ่ ฉันดีใจที่เรามีวิธี 'แนะนำ' น้อยลงในการกำหนดประเภทในขณะนี้
สลิล

2
@Trylks: ความสามารถในการปฏิบัติต่อวัตถุเป็นลำดับของคู่คีย์ - ค่า เกือบทุกอย่างที่เป็นของ clojure สามารถถือเป็นลำดับได้ซึ่งมีประสิทธิภาพมาก
Rob Lachlan

proxyบางครั้งเป็นที่ต้องการเนื่องจากอนุญาตให้ปรับเปลี่ยนวิธีการในขณะรันไทม์ (เช่นThe Joy of Clojure , 2nd ed. ชี้ให้เห็นว่าสิ่งนี้อาจมีประโยชน์สำหรับการแก้ไขการโทรกลับในตัวจัดการเว็บ)
อังคาร

52

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

หากคุณไม่ต้องการการทำงานร่วมกันของ Java 99% ของเวลาที่ดีที่สุดในการยึดติดกับ Defrecord หรือแผนที่ Clojure แบบธรรมดา

  • ใช้ Defrecord หากคุณต้องการใช้โปรโตคอล
  • มิฉะนั้นแผนที่ Clojure ปกติอาจจะง่ายและเข้าใจได้มากที่สุด

หากความต้องการของคุณซับซ้อนมากขึ้นผังงานต่อไปนี้เป็นเครื่องมือที่ยอดเยี่ยมในการอธิบายว่าเหตุใดคุณจึงเลือกตัวเลือกเหล่านี้มากกว่าตัวเลือกอื่น ๆ :

http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/

โฟลว์ชาร์ตสำหรับการเลือกแบบฟอร์มการกำหนดประเภทของ clojure


1
ขอบคุณมากสำหรับลิงค์ไปยังผังงาน ช่วยให้บล็อกนี้เป็นของผู้เขียนร่วมของ O’illy's - Programming Clojure ฉันคิดว่าการตัดสินใจนี้ค่อนข้างซับซ้อน ความแตกต่างระหว่างอินเทอร์เฟซและคลาสคอนกรีตหรือไม่หรือจำเป็นต้องกำหนดวิธีการแบบคงที่หรือไม่หรือประเภทที่ระบุชื่อหรือประเภทที่ไม่ระบุตัวตนมีมากมายจนต้องใช้โครงสร้างภาษาอื่นหรือไม่?
สลิล

4
ความแตกต่างไม่ได้มากมาย แต่มีความแตกต่างกันในเชิงปรัชญาในแง่ของสิ่งที่คุณพยายามจะบรรลุ ฉันคิดว่าวิธีการต่างๆใน Clojure สะท้อนให้เห็นถึงความแตกต่างพื้นฐานเหล่านี้ซึ่งเป็นเหตุผลที่ดีว่าทำไมจึงควรตั้งชื่อที่แตกต่างกัน
mikera

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