ต้นแบบที่ใช้กับการสืบทอดตามคลาส


208

ใน JavaScript วัตถุทุกตัวในเวลาเดียวกันเป็นอินสแตนซ์และคลาส ในการรับมรดกคุณสามารถใช้อินสแตนซ์ของวัตถุใด ๆ ก็ได้เป็นต้นแบบ

ใน Python, C ++ ฯลฯ มีคลาสและอินสแตนซ์เป็นแนวคิดแยกต่างหาก ในการทำการสืบทอดคุณต้องใช้คลาสฐานเพื่อสร้างคลาสใหม่ซึ่งสามารถใช้เพื่อสร้างอินสแตนซ์ที่ได้รับ

ทำไม JavaScript ไปในทิศทางนี้ (การวางวัตถุตามต้นแบบ) อะไรคือข้อดี (และข้อเสีย) ของต้นแบบ OO ที่เกี่ยวกับแบบดั้งเดิม OO แบบคลาส?


10
JavaScript ได้รับอิทธิพลจาก Self ซึ่งเป็นภาษาแรกที่มีการสืบทอดต้นแบบ ในช่วงเวลานั้นการสืบทอดคลาสสิกเป็นความโกรธแค้นครั้งแรกใน Simula อย่างไรก็ตามการสืบทอดแบบดั้งเดิมนั้นซับซ้อนเกินไป จากนั้น David Ungar และ Randall Smith มี epiphany หลังจากอ่าน GEB - "เหตุการณ์ที่เฉพาะเจาะจงที่สุดสามารถใช้เป็นตัวอย่างทั่วไปของคลาสของเหตุการณ์" พวกเขาตระหนักว่าคลาสไม่จำเป็นสำหรับการเขียนโปรแกรมเชิงวัตถุ ด้วยตนเองจึงเกิด หากต้องการทราบว่ามรดกต้นแบบดีกว่ามรดกดั้งเดิมอย่างไรอ่านได้ที่นี่: stackoverflow.com/a/16872315/783743 =)
Aadit M Shah

@AaditMShah คืออะไร / ใครGEB?
อเล็กซ์

3
@Alex GEB เป็นหนังสือที่เขียนโดย Douglas Hofstadter มันเป็นตัวย่อของGödel Escher Bach Kurt Gödelเป็นนักคณิตศาสตร์ Escher เป็นศิลปิน บาคเป็นนักเปียโน
Aadit M Shah

คำตอบ:


201

มีปัญหาเกี่ยวกับคำศัพท์ประมาณร้อยที่นี่ส่วนใหญ่สร้างขึ้นรอบ ๆ ใครบางคน (ไม่ใช่คุณ) พยายามทำให้ความคิดของพวกเขาฟังดูเหมือนดีที่สุด

ภาษาเชิงวัตถุทั้งหมดจะต้องสามารถจัดการกับแนวคิดหลายอย่าง:

  1. การห่อหุ้มข้อมูลพร้อมกับการดำเนินการที่เกี่ยวข้องกับข้อมูลที่รู้จักกันหลากหลายในฐานะสมาชิกข้อมูลและฟังก์ชั่นสมาชิกหรือเป็นข้อมูลและวิธีการเหนือสิ่งอื่นใด
  2. การสืบทอดความสามารถในการพูดว่าวัตถุเหล่านี้เป็นเหมือนชุดของวัตถุอื่นยกเว้นการเปลี่ยนแปลงเหล่านี้
  3. polymorphism ("หลายรูปร่าง") ซึ่งวัตถุตัดสินใจด้วยตัวเองว่าจะใช้วิธีการใดเพื่อให้คุณสามารถพึ่งพาภาษาเพื่อกำหนดเส้นทางคำขอของคุณได้อย่างถูกต้อง

ตอนนี้เท่าที่เปรียบเทียบ:

สิ่งแรกคือคำถาม "คลาส" กับ "ต้นแบบ" ทั้งหมด ความคิดเริ่มต้นใน Simula ที่มีวิธีการเรียนตามแต่ละชั้นเรียนเป็นชุดของวัตถุที่ใช้พื้นที่รัฐเดียวกัน (อ่าน "ค่าที่เป็นไปได้") และการดำเนินงานเดียวกันจึงสร้างชั้นเทียบเท่า หากคุณมองย้อนกลับไปที่สมอลทอล์คเนื่องจากคุณสามารถเปิดคลาสและเพิ่มเมธอดนี่เป็นวิธีเดียวกับที่คุณสามารถทำได้ใน Javascript

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

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

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

เหตุผลที่สิ้นสุดลงในสคริปต์ Javascript / ECMA นั้นโดยทั่วไปแล้วเมื่อเราเริ่มต้นเมื่อ 10 ปีที่แล้วเรากำลังติดต่อกับคอมพิวเตอร์ที่ทรงพลังน้อยกว่าและเบราว์เซอร์ที่ซับซ้อนน้อยกว่ามาก การเลือกวิธีที่ใช้ต้นแบบหมายความว่าล่ามอาจง่ายมากในขณะที่รักษาคุณสมบัติที่ต้องการของการวางแนววัตถุ


1
ใช่ paragaph นั้นอ่านเหมือนว่าฉันหมายถึงอย่างอื่นหรือไม่? Dahl และ Nyqvist มาพร้อมกับ "class" เป็นชุดของสิ่งต่าง ๆ ที่มีลายเซ็นวิธีการเดียวกัน
ชาร์ลีมาร์ติน

1
การเปลี่ยนแปลงนั้นบอกว่าดีขึ้นไหม?
ชาร์ลีมาร์ติน

2
ไม่ขอโทษ CLOS มาจากปลาย 80's dreamsongs.com/CLOS.html Smalltalk จาก 1980 en.wikipedia.org/wiki/Smalltalkและ Simula พร้อมการวางแนววัตถุเต็มรูปแบบตั้งแต่ปี 1967-68 en.wikipedia.org/wiki/Simula
Charlie มาร์ติน

3
@Stephano พวกเขาไม่ได้แยกความแตกต่างเช่นนั้นทั้งหมด: Python, Ruby, Smalltalk ใช้พจนานุกรมสำหรับการค้นหาวิธีการและ javascript และ Self มีคลาส ในระดับหนึ่งคุณอาจโต้แย้งว่าความแตกต่างก็คือภาษาต้นแบบที่เน้นการเปิดเผยการใช้งานของพวกเขา ดังนั้นจึงเป็นเรื่องดีที่จะไม่ทำให้เป็นเรื่องใหญ่: อาจเป็นมากกว่าข้อโต้แย้งระหว่าง EMACS และ vi
ชาร์ลีมาร์ติน

21
คำตอบที่มีประโยชน์ +1 ขยะที่มีประโยชน์น้อยลงในความคิดเห็น ฉันหมายความว่ามันสร้างความแตกต่างไม่ว่า CLOS หรือ Smalltalk เป็นครั้งแรกหรือไม่ คนส่วนใหญ่ที่นี่ไม่ใช่นักประวัติศาสตร์อย่างไรก็ตาม
Adam Arold

40

การเปรียบเทียบซึ่งจะลำเอียงเล็กน้อยต่อต้นแบบตามแนวทางสามารถพบได้ในกระดาษด้วยตนเอง: พลังของความเรียบง่าย กระดาษทำให้ข้อโต้แย้งต่อไปนี้ในความโปรดปรานของต้นแบบ:

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

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

รองรับวัตถุที่ไม่เหมือนใคร Self จัดเตรียมเฟรมเวิร์กที่สามารถรวมวัตถุที่ไม่เหมือนใครเข้ากับพฤติกรรมของตนเองได้อย่างง่ายดาย เนื่องจากแต่ละวัตถุมีชื่อช่องและช่องสามารถเก็บสถานะหรือพฤติกรรมวัตถุใด ๆ สามารถมีช่องหรือลักษณะการทำงานที่ไม่ซ้ำกัน ระบบที่ใช้คลาสได้รับการออกแบบมาสำหรับสถานการณ์ที่มีวัตถุจำนวนมากที่มีพฤติกรรมเหมือนกัน ไม่มีการสนับสนุนทางภาษาสำหรับวัตถุที่มีพฤติกรรมที่เป็นเอกลักษณ์ของตัวเองและเป็นที่น่าอึดอัดใจที่จะสร้างคลาสที่รับประกันว่าจะมีเพียงหนึ่งอินสแตนซ์ [ คิดว่ารูปแบบซิงเกิล ] ตนเองทนทุกข์ทรมานจากข้อเสียเหล่านี้ วัตถุใด ๆ ที่สามารถปรับแต่งด้วยพฤติกรรมของตัวเอง วัตถุที่ไม่ซ้ำกันสามารถเก็บพฤติกรรมที่ไม่ซ้ำกันและไม่จำเป็นต้องมี "อินสแตนซ์" แยกต่างหาก

การกำจัดของเมตาถอยหลัง ไม่มีออบเจ็กต์ในระบบที่ใช้คลาสเป็นแบบพอเพียงได้ วัตถุอื่น (ระดับเดียวกัน) เป็นสิ่งจำเป็นในการแสดงโครงสร้างและพฤติกรรม สิ่งนี้นำไปสู่ ​​meta-regress ทางแนวคิดที่ไม่มีขีด จำกัด : a pointเป็นตัวอย่างของคลาสPointซึ่งเป็นตัวอย่างของ metaclass Pointซึ่งเป็นตัวอย่างของ metametaclass Pointซึ่งเป็น infinitum ในทางตรงกันข้ามในระบบที่ใช้ต้นแบบวัตถุสามารถมีพฤติกรรมของตัวเอง ไม่จำเป็นต้องมีวัตถุอื่นในการหายใจชีวิตเข้าไป ต้นแบบกำจัด meta-regress

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


5
RE: กำจัด meta-regress: ใน Common Object Lisp ซึ่งเป็นคลาสที่ใช้, a pointเป็นตัวอย่างของคลาสPointซึ่งเป็นตัวอย่างของ metaclass standard-classซึ่งเป็นตัวอย่างของตัวเองโฆษณาขั้นสุดท้าย
Max Nanasy

ลิงก์ไปยังเอกสารด้วยตนเองนั้นตายแล้ว ลิงค์การทำงาน: ตนเอง: พลังแห่งความเรียบง่าย | บรรณานุกรมตนเอง
1201917

24

คุณควรตรวจสอบหนังสือยอดเยี่ยมเกี่ยวกับ JavaScriptโดยดักลาส Crockford มันให้คำอธิบายที่ดีมากเกี่ยวกับการตัดสินใจออกแบบโดยผู้สร้าง JavaScript

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

ดังนั้นฉันคิดว่ามีข้อดีสำหรับต้นแบบ OO ตามที่ใช้ใน JavaScript:

  1. เหมาะในสภาพแวดล้อมที่พิมพ์หลวมไม่จำเป็นต้องกำหนดประเภทที่ชัดเจน
  2. ทำให้การใช้รูปแบบซิงเกิลเป็นเรื่องง่ายอย่างไม่น่าเชื่อ (เปรียบเทียบ JavaScript และ Java ในเรื่องนี้และคุณจะรู้ว่าฉันกำลังพูดถึงอะไร)
  3. ให้วิธีการใช้วิธีการของวัตถุในบริบทของวัตถุที่แตกต่างกันการเพิ่มและแทนที่วิธีการแบบไดนามิกจากวัตถุอื่น ๆ (สิ่งที่เป็นไปไม่ได้ในภาษาที่พิมพ์อย่างยิ่ง)

นี่คือข้อเสียของต้นแบบ OO:

  1. ไม่มีวิธีง่ายๆในการใช้งานตัวแปรส่วนตัว เป็นไปได้ที่จะใช้ vars ส่วนตัวโดยใช้พ่อมดของCrockfordโดยใช้closuresแต่ไม่เป็นเรื่องเล็กน้อยเหมือนกับการใช้ตัวแปรส่วนตัวใน Java หรือ C #
  2. ฉันยังไม่รู้วิธีใช้หลายมรดก (สำหรับมูลค่าของมัน) ใน JavaScript

2
เพียงใช้หลักการตั้งชื่อสำหรับ vars ส่วนตัวเช่นเดียวกับ Python
aehlke

1
ใน js วิธีที่จะทำ vars ส่วนตัวอยู่กับการปิดและที่เป็นอิสระจากประเภทมรดกที่คุณเลือก
Benja

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