JavaRush /จาวาบล็อก /Random-TH /มรดกเป็นปรากฏการณ์
articles
ระดับ

มรดกเป็นปรากฏการณ์

เผยแพร่ในกลุ่ม
บอกตามตรงว่าตอนแรกฉันไม่ได้วางแผนบทความนี้ ฉันถือว่าประเด็นที่ฉันต้องการพูดคุยที่นี่เป็นเรื่องเล็กน้อยและไม่ควรค่าแก่การกล่าวถึงด้วยซ้ำ อย่างไรก็ตาม ในระหว่างการเขียนบทความสำหรับไซต์นี้ ฉันได้หยิบยกการอภิปรายเกี่ยวกับมรดกหลายอย่างในฟอรัมหนึ่ง ผลปรากฏว่านักพัฒนาส่วนใหญ่มีความเข้าใจเกี่ยวกับการสืบทอดที่คลุมเครือมาก และด้วยเหตุนี้เขาจึงทำผิดพลาดมากมาย เนื่องจากการสืบทอดเป็นหนึ่งในคุณสมบัติที่สำคัญที่สุดของ OOP (หากไม่ใช่สิ่งที่สำคัญที่สุด!) ฉันจึงตัดสินใจอุทิศบทความแยกต่างหากเกี่ยวกับปรากฏการณ์นี้ * * * ก่อนอื่น ฉันต้องการแยกความแตกต่างระหว่างสองแนวคิด - วัตถุและคลาส แนวคิดเหล่านี้สับสนอยู่ตลอดเวลา ในขณะเดียวกันก็เป็นศูนย์กลางของ OOP และในความคิดของฉัน จำเป็นต้องทราบความแตกต่างระหว่างกัน ดังนั้นวัตถุ โดยพื้นฐานแล้วมันเป็นอะไรก็ได้ นี่คือลูกบาศก์ ทำด้วยไม้, น้ำเงิน. ความยาวของขอบ 5 ซม. นี่คือวัตถุ และมีปิรามิด พลาสติกสีแดง ซี่โครง 10 ซม. นี่ก็เป็นวัตถุเช่นกัน พวกเขามีอะไรเหมือนกัน? ขนาดแตกต่างกัน รูปร่างที่แตกต่าง วัสดุที่แตกต่าง อย่างไรก็ตาม พวกเขามีบางอย่างที่เหมือนกัน ประการแรก ทั้งลูกบาศก์และปิรามิดนั้นเป็นรูปทรงหลายเหลี่ยมปกติ เหล่านั้น. ผลรวมของจำนวนจุดยอดและจำนวนหน้ามากกว่าจำนวนขอบ 2 ไกลออกไป. รูปร่างทั้งสองมีใบหน้า ขอบ และจุดยอด ร่างทั้งสองมีลักษณะเฉพาะเท่ากับขนาดซี่โครง สามารถหมุนได้ทั้ง 2 แบบ สามารถวาดทั้งสองร่างได้ คุณสมบัติสองรายการสุดท้ายเป็นพฤติกรรมอยู่แล้ว และอื่นๆ การฝึกเขียนโปรแกรมแสดงให้เห็นว่าการทำงานกับวัตถุที่เป็นเนื้อเดียวกันนั้นง่ายกว่าการใช้วัตถุที่ต่างกันมาก และเนื่องจากยังมีบางสิ่งที่เหมือนกันระหว่างตัวเลขเหล่านี้ จึงมีความปรารถนาที่จะเน้นย้ำถึงความเหมือนกันนี้ นี่คือจุดที่แนวคิดเรื่องชั้นเรียนเข้ามามีบทบาท ดังนั้นคำจำกัดความ
คลาสเป็นตัวอธิบายคุณสมบัติทั่วไปของกลุ่มของวัตถุ คุณสมบัติเหล่านี้สามารถเป็นได้ทั้งลักษณะของวัตถุ (ขนาด น้ำหนัก สี ฯลฯ) และพฤติกรรม บทบาท ฯลฯ
ความคิดเห็น คำว่า “ทั้งหมด” (คำอธิบายถึงคุณสมบัติทั้งหมด) ไม่ได้ถูกพูด ซึ่งหมายความว่าวัตถุใด ๆ สามารถอยู่ในคลาสที่แตกต่างกันได้หลายคลาส การสืบทอดเป็นปรากฏการณ์ - 1 ลองใช้ตัวอย่างเดียวกันกับรูปทรงเรขาคณิตเป็นพื้นฐาน คำอธิบายทั่วไปที่สุดคือรูปทรงหลายเหลี่ยมปกติ โดยไม่คำนึงถึงขนาดขอบ จำนวนหน้า และจุดยอด สิ่งเดียวที่เรารู้คือรูปนี้มีจุดยอด ขอบ และด้าน และความยาวของขอบเท่ากัน ไกลออกไป. เราสามารถทำให้คำอธิบายเฉพาะเจาะจงมากขึ้นได้ สมมติว่าเราต้องการวาดรูป หลายเหลี่ยม นี้ ให้เราแนะนำแนวคิดเช่น การวาดรูปหลายเหลี่ยมปกติ เราต้องการอะไรในการวาดภาพ? คำอธิบายของวิธีการวาดทั่วไปที่ไม่ขึ้นอยู่กับพิกัดจุดยอดเฉพาะ บางทีสีของวัตถุ ตอนนี้เรามาแนะนำคลาส Cubeและ Tetrahedronกัน วัตถุที่อยู่ในคลาสเหล่านี้เป็นรูปทรงหลายเหลี่ยมปกติอย่างแน่นอน ข้อแตกต่างเพียงอย่างเดียวคือจำนวนจุดยอด ขอบ และพื้นผิวได้รับการแก้ไขอย่างเคร่งครัดแล้วสำหรับแต่ละคลาสใหม่ นอกจากนี้เมื่อทราบประเภทของตัวเลขเฉพาะแล้วเราสามารถให้คำอธิบายวิธีการวาดได้ ซึ่งหมายความว่าอ็อบเจ็กต์ใดๆ ของ คลาสคิวบ์หรือจัตุรมุข ก็เป็นอ็อบเจ็กต์ของ คลาส โพลีเฮดรอนปกติ ที่วาดไว้เช่นกัน มีลำดับชั้นของชั้นเรียน ในลำดับชั้นนี้ เราลงมาจากคำอธิบายทั่วไปที่สุดไปสู่คำอธิบายเฉพาะเจาะจงที่สุด โปรดทราบว่าออบเจ็กต์ของคลาสใดๆ ยังเหมาะสมกับคำอธิบายของคลาสทั่วไปในลำดับชั้นด้วย ความสัมพันธ์ในชั้นเรียนนี้เรียกว่าการ สืบทอด คลาสย่อยแต่ละคลาสสืบทอดคุณสมบัติทั้งหมดของพาเรนต์ โดยทั่วไปและ (อาจ) เพิ่มคุณสมบัติบางอย่างของตัวเองให้กับคุณสมบัติเหล่านี้ หรือจะแทนที่คุณสมบัติบางอย่างของคลาสพาเรนต์ ที่นี่ฉันต้องการอ้างอิงจากหนังสือคลาสสิกของ Gradi Bucha เกี่ยวกับการออกแบบเชิงวัตถุ:
ดังนั้นการสืบทอดจึงกำหนดลำดับชั้น "เป็น" ระหว่างคลาส โดยที่คลาสย่อยสืบทอดมาจากซูเปอร์คลาสตั้งแต่หนึ่งคลาสขึ้นไป อันที่จริงนี่คือการทดสอบสารสีน้ำเงินสำหรับการสืบทอด เมื่อพิจารณาถึงคลาส A และ B ถ้า A "ไม่ใช่" ชนิดของ B ดังนั้น A ก็ไม่ควรจะเป็นคลาสย่อยของ B
แปลออกมาได้ประมาณนี้
การสืบทอดจึงกำหนดลำดับชั้น "เป็น" ระหว่างคลาส โดยที่คลาสย่อยสืบทอดมาจากซูเปอร์คลาสตั้งแต่หนึ่งคลาสขึ้นไป ในความเป็นจริง นี่คือการทดสอบที่กำหนด (ตามตัวอักษร การทดสอบสารสีน้ำเงิน บันทึกของฉัน) สำหรับการสืบทอด หากเรามีคลาส A และ B และหากคลาส A "ไม่ใช่" ตัวแปรของคลาส B ดังนั้น A จะต้องไม่เป็นคลาสย่อยของ B
คนที่อ่านมาถึงขนาดนี้คงจะหมุนนิ้วไปที่ขมับด้วยความงุนงง ความคิดแรกคือนี่เป็นเรื่องเล็กน้อย! นี่เป็นเรื่องจริง แต่ถ้าคุณรู้ว่าฉันเคยเห็นลำดับชั้นมรดกบ้าๆ บอ ๆ มามากขนาดไหน! ในการสนทนาที่ผมพูดถึงในตอนต้น หนึ่งในผู้เข้าร่วมได้รับมรดกรถถังจาก... ปืนกลอย่างจริงจัง!!! ด้วยเหตุผลง่ายๆ ที่รถถังมีปืนกล และนี่คือข้อผิดพลาดที่พบบ่อยที่สุด การสืบทอดสับสนกับการรวมกลุ่ม - การรวมวัตถุหนึ่งไว้ในอีกวัตถุหนึ่ง รถถังไม่ใช่ปืนกล แต่มีอยู่หนึ่งกระบอก และเนื่องจากข้อผิดพลาดนี้ ส่วนใหญ่มักมีความปรารถนาที่จะใช้การสืบทอดหลายรายการ ตอนนี้เรามาดูโดยตรงที่ Java มีอะไรในแง่ของมรดก? คลาสในภาษามีสองประเภท - คลาสที่มีความสามารถในการนำไปใช้งาน และคลาสที่ไม่สามารถทำได้ ส่วนหลังเรียกว่าอินเทอร์เฟซแม้ว่าโดยพื้นฐานแล้วจะเป็นคลาสนามธรรมที่สมบูรณ์ก็ตาม การสืบทอดเป็นปรากฏการณ์ - 2 ดังนั้น ภาษาจึงอนุญาตให้คุณสืบทอดคลาสจากคลาสอื่นที่อาจมีการนำไปใช้งาน แต่มาจากหนึ่งเดียวเท่านั้น! ให้ฉันอธิบายว่าทำไมสิ่งนี้ถึงทำ ประเด็นก็คือว่าการใช้งานแต่ละครั้งสามารถจัดการกับส่วนของมันเท่านั้น - ด้วยตัวแปรและวิธีการเหล่านั้นที่รู้ และถึงแม้ว่าเราจะสืบทอดคลาส Cจาก Aและ Bดังนั้นเมธอด processA ที่สืบทอดมาจากคลาส A จะสามารถทำงานได้กับตัวแปรภายใน a เท่านั้น เพราะมันไม่รู้อะไรเลยเกี่ยวกับ bเช่นเดียวกับที่มันไม่รู้อะไรเลยเกี่ยวกับc และเมธอด processC ในทำนองเดียวกัน วิธี processB สามารถทำงานกับตัวแปร b เท่านั้น นั่นคือโดยพื้นฐานแล้วส่วนที่สืบทอดมาจะถูกแยกออกจากกัน คลาส C สามารถทำงานร่วมกับพวกมันได้อย่างแน่นอน แต่ก็สามารถทำงานร่วมกับส่วนเหล่านี้ได้เช่นกัน หากพวกมันถูกรวมไว้เป็นส่วนหนึ่งของมันแทนที่จะสืบทอดมา อย่างไรก็ตาม ยังมีเรื่องน่ารำคาญอีกประการหนึ่ง นั่นคือชื่อที่ทับซ้อนกัน ถ้าเมธอด processAและ processBถูกตั้งชื่อเหมือนกัน เช่น process แล้วการเรียกเมธอด โปร เซส ของคลาส C จะมีผล อย่างไร วิธีใดในสองวิธีที่จะเรียกว่า? แน่นอนว่า C++ มีการควบคุมในสถานการณ์นี้ แต่ไม่ได้เพิ่มความกลมกลืนให้กับภาษา ดังนั้น การสืบทอดการใช้งานไม่ได้ให้ข้อดี แต่มีข้อเสียอยู่ ด้วยเหตุนี้ การสืบทอดการใช้งานนี้ใน Java จึงถูกยกเลิก อย่างไรก็ตาม นักพัฒนายังคงเหลือตัวเลือกดังกล่าวสำหรับการสืบทอดหลายรายการเป็นการสืบทอดจากอินเทอร์เฟซ ในแง่ Java การใช้งานอินเทอร์เฟซ อินเทอร์เฟซคืออะไร? ชุดวิธีการ (ขณะนี้เราไม่ได้พิจารณาคำจำกัดความของค่าคงที่ในอินเทอร์เฟซ ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ ที่นี่ ) วิธีการคืออะไร? และวิธีการซึ่งเป็นแกนหลักจะกำหนดพฤติกรรมของวัตถุ ไม่ใช่เรื่องบังเอิญที่ชื่อของเกือบทุกวิธีจะมีการกระทำ - getXXX , DrawXXX , countXXXฯลฯ และเนื่องจากอินเทอร์เฟซคือชุดของวิธีการ อินเทอร์เฟซจึง เป็น ปัจจัยกำหนดพฤติกรรมจริงๆ ตัวเลือกอื่นสำหรับการใช้อินเทอร์เฟซคือการกำหนดบทบาทของออบเจ็กต์ ผู้สังเกตการณ์ ผู้ฟังฯลฯ ในกรณีนี้ วิธีการนี้เป็นศูนย์รวมของการตอบสนองต่อเหตุการณ์ภายนอกบางอย่าง นั่นคือพฤติกรรมอีกครั้ง วัตถุสามารถมีพฤติกรรมที่แตกต่างกันได้หลายอย่าง หากจำเป็นต้องเรนเดอร์ มันก็เรนเดอร์ ถ้าเขาจำเป็นต้องรอด เขาก็รอด อืม ฯลฯ ดังนั้นความสามารถในการสืบทอดจากคลาสที่กำหนดพฤติกรรมจึงมีประโยชน์มาก ในทำนองเดียวกัน วัตถุสามารถมีบทบาทที่แตกต่างกันได้หลายอย่าง อย่างไรก็ตาม การนำไปปฏิบัติพฤติกรรมล้วนขึ้นอยู่กับจิตสำนึกของชนชั้นเด็กทั้งสิ้น การสืบทอดจากอินเทอร์เฟซ (การใช้งาน) บอกว่าอ็อบเจ็กต์ของคลาสนี้ควรจะสามารถทำสิ่งนี้และสิ่งนั้นได้ และวิธีนี้จะทำการพิจารณาอย่างเป็นอิสระโดยแต่ละคลาสที่ใช้อินเทอร์เฟซ กลับไปที่ข้อผิดพลาดในการสืบทอด ประสบการณ์ของฉันในการพัฒนาระบบต่างๆ แสดงให้เห็นว่าการมีมรดกจากอินเทอร์เฟซ คุณสามารถใช้งานระบบใดก็ได้โดยไม่ต้องใช้มรดกการใช้งานหลายรายการ ดังนั้นเมื่อฉันพบข้อร้องเรียนเกี่ยวกับการขาดการสืบทอดหลายรายการในรูปแบบที่มีอยู่ใน C ++ นี่เป็นสัญญาณที่ชัดเจนว่าการออกแบบที่ไม่ถูกต้องสำหรับฉัน ข้อผิดพลาดที่พบบ่อยที่สุดที่เกิดขึ้นคือสิ่งที่ฉันได้กล่าวไปแล้ว - การสืบทอดสับสนกับการรวมกลุ่ม บางครั้งสิ่งนี้เกิดขึ้นเนื่องจากการสันนิษฐานที่ไม่ถูกต้อง เหล่านั้น. ยกตัวอย่างเช่น มาตรวัดความเร็ว แย้งว่าความเร็วสามารถวัดได้โดยการวัดระยะทางและเวลาเท่านั้น หลังจากนั้น มาตรวัดความเร็วจะสืบทอดมาจากไม้บรรทัดและนาฬิกาได้สำเร็จ จึงกลายเป็นไม้บรรทัดและนาฬิกาตามคำจำกัดความของ มรดก (คำขอของฉันในการวัดเวลาด้วยมาตรวัดความเร็วมักจะตอบเป็นเรื่องตลก หรือไม่ตอบเลย) ข้อผิดพลาดคืออะไร ในสถานที่. ความจริงก็คือมาตรวัดความเร็วไม่ได้วัดเวลา และระยะทางอีกด้วย มาตรวัดระยะทางซึ่งพบได้ในมาตรวัดความเร็วใด ๆ เป็นตัวอย่างคลาสสิกของอุปกรณ์ตัวที่สองในตัวเรือนเดียวกันนั่นคือ การรวมตัว ไม่จำเป็นต้องวัดความเร็ว สามารถลบออกทั้งหมดได้ - ซึ่งจะไม่ส่งผลต่อการวัดความเร็ว แต่อย่างใด บางครั้งความผิดพลาดดังกล่าวเกิดขึ้นโดยเจตนา นี่แย่กว่ามาก “ใช่ ฉันรู้ว่ามันผิด แต่มันสะดวกกว่าสำหรับฉัน” สิ่งนี้จะนำไปสู่อะไร? แต่นี่คือสิ่งที่: เราจะสืบทอดรถถังจากปืนใหญ่และปืนกล วิธีนี้สะดวกกว่า เป็นผลให้รถถังกลายเป็นปืนใหญ่และปืนกล ต่อไปเราจะติดตั้งปืนกลสองกระบอกและปืนใหญ่หนึ่งกระบอกให้กับเครื่องบิน เราได้อะไร? เครื่องบินที่มีอาวุธแขวนลอยอยู่ในรูปของรถถังสามคัน! เพราะมีคนแน่นอนที่ใช้รถถังเป็นปืนกลโดยไม่เข้าใจ เฉพาะตามลำดับชั้นการสืบทอด และเขาจะพูดถูกอย่างแน่นอน เพราะผู้ที่ออกแบบลำดับชั้นดังกล่าวทำผิดพลาด
โดยทั่วไปแล้ว ฉันไม่เข้าใจแนวทาง " วิธีนี้สะดวกกว่า สำหรับฉัน " จริงๆ การเขียนแบบผู้ฟังนั้นสะดวก และคนที่บอกว่าไวยากรณ์พื้นฐานนั้นไม่แน่นอน แน่นอนว่าฉันพูดเกินจริง แต่แนวคิดหลักยังคงอยู่ - นอกเหนือจากความสะดวกสบายชั่วขณะแล้วยังมีสิ่งที่เรียกว่าการรู้หนังสืออีกด้วย แนวคิดนี้กำหนดขึ้นจากประสบการณ์ของผู้คนจำนวนมาก อันที่จริง นี่คือสิ่งที่ในภาษาอังกฤษเรียกว่า "แนวปฏิบัติที่ดีที่สุด" ซึ่งเป็นทางออกที่ดีที่สุด และบ่อยครั้งที่วิธีแก้ปัญหาที่ดูง่ายกว่านั้นนำมาซึ่งปัญหามากมายในอนาคต
แน่นอนว่าตัวอย่างนี้เกินจริงอย่างมากและดังนั้นจึงไร้สาระ อย่างไรก็ตาม มีกรณีที่เห็นได้ชัดเจนน้อยกว่าที่ยังนำไปสู่ผลที่ตามมาที่เป็นหายนะ ด้วยการสืบทอดจากออบเจ็กต์ แทนที่จะรวมเข้าด้วยกัน นักพัฒนาจะทำให้ทุกคนสามารถใช้ฟังก์ชันการทำงานของออบเจ็กต์หลักได้โดยตรง ด้วยทั้งหมดที่มันหมายถึง ลองนึกภาพว่าคุณมีคลาสที่ทำงานกับฐานข้อมูล DBManager คุณสร้างคลาสอื่นที่จะทำงานกับข้อมูลของคุณโดยใช้ DBManager - DataManager คลาสนี้จะดำเนินการควบคุมข้อมูล การแปลง การดำเนินการเพิ่มเติม ฯลฯ โดยทั่วไปจะเป็นชั้นระหว่างชั้นธุรกิจและชั้นฐาน หากคุณสืบทอด DataManager จาก DBManager ใครก็ตามที่ใช้ DataManager จะสามารถเข้าถึงฐานข้อมูลได้โดยตรง ดังนั้นเขาจึงสามารถดำเนินการใด ๆ ได้โดยไม่ต้องผ่านการควบคุม การแปลงร่าง ฯลฯ โอเค สมมติว่าไม่มีใครต้องการก่อให้เกิดอันตรายโดยเจตนาและการกระทำโดยตรงจะมีความสามารถ แต่! สมมติว่าฐานมีการเปลี่ยนแปลง ฉันหมายถึงหลักการควบคุมหรือการเปลี่ยนแปลงบางอย่างเปลี่ยนไป DataManager มีการเปลี่ยนแปลง แต่โค้ดที่เคยทำงานโดยตรงกับฐานข้อมูลก่อนหน้านี้จะยังคงใช้งานได้ต่อไป พวกเขาคงจะจำเขาไม่ได้ ผลลัพธ์จะเป็นข้อผิดพลาดของคลาสที่ผู้ที่มองหามันจะกลายเป็นสีเทา มันจะไม่เกิดขึ้นกับใครก็ตามที่พวกเขาทำงานกับฐานข้อมูลโดยข้าม DataManager ยังไงก็ตามตัวอย่างจากชีวิตจริง ใช้เวลานานมากในการค้นหาข้อผิดพลาด สุดท้ายนี้ฉันจะพูดอีกครั้ง การสืบทอดควรใช้เมื่อมีความสัมพันธ์ "เป็น" เท่านั้น เพราะนี่คือแก่นแท้ของการสืบทอด - ความสามารถในการใช้วัตถุของคลาสลูกเป็นวัตถุของคลาสฐาน หากไม่มีความสัมพันธ์แบบ “เป็น” ระหว่างคลาส ก็ไม่ควรมีการสืบทอด!!! ไม่เคยและไม่ว่าในสถานการณ์ใดก็ตาม และยิ่งกว่านั้น – เพียงเพราะมันสะดวกมาก ลิงก์ไปยังแหล่งที่มาดั้งเดิม: http://www.skipy.ru/philosophy/inheritance.html
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION