องค์ประกอบมากกว่ามรดก แต่


13

ฉันพยายามสอนตัวเองเกี่ยวกับวิศวกรรมซอฟต์แวร์และการหาข้อมูลที่ขัดแย้งกันซึ่งทำให้ฉันสับสน

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

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

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

เนื่องจากฉันคุ้นเคยกับ PHP มากที่สุดฉันจึงใช้มันเพื่อพัฒนาทักษะ OOP / SE ของฉันก่อนที่จะย้ายไปใช้ภาษาอื่นและถ่ายโอนทักษะ SE ที่เพิ่งได้รับมาดังนั้นตัวอย่างการใช้ PHP จะได้รับการชื่นชมมากที่สุด


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

2
"ความโปรดปราน X Y มากกว่า" ไม่ได้หมายความว่าไม่เคยใช้ Y เพียงแค่คิดว่าถ้า X จะดีกว่า
ริชาร์ดซ่า

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

1
@MasonWheeler ไม่มีกรณีการใช้งานที่ถูกต้องสำหรับการสืบทอด อย่างน้อยก็เป็น "ความชั่วร้าย" คุณสมบัติเป็น "goto"
David Arno

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

คำตอบ:


19

การจัดองค์ประกอบเหนือมรดกหมายความว่าเมื่อคุณต้องการใช้ซ้ำหรือขยายฟังก์ชันการทำงานของคลาสที่มีอยู่บ่อยครั้งจะเหมาะสมกว่าที่จะสร้างคลาสอื่นที่จะ 'ตัด' คลาสที่มีอยู่และใช้งานภายใน รูปแบบมัณฑนากรเป็นตัวอย่างของสิ่งนี้

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

วิธีเทมเพลตเป็นตัวอย่างที่ดีของกรณีที่การสืบทอดมีความเหมาะสม

ดูคำตอบนี้สำหรับแนวทางในการเลือกระหว่างองค์ประกอบและการสืบทอด


+1 สำหรับการชี้ให้เห็นว่าในกรณีที่มีการนำคลาสมาใช้ใหม่บางส่วนส่วนที่ไม่ได้ใช้จะถูกละเว้นด้วยการจัดองค์ประกอบที่สะอาดกว่าการสืบทอด
Lawrence

4

ฉันไม่คุ้นเคยกับ PHP ในการให้ตัวอย่างที่เป็นรูปธรรมแก่คุณในภาษานั้น แต่นี่เป็นแนวทางบางประการที่ฉันพบว่ามีประโยชน์

อินเทอร์เฟซ / คุณลักษณะเป็นประโยชน์สำหรับการกำหนดพฤติกรรมข้ามคลาสต่างๆที่อาจมีความเหมือนกันเล็กน้อย

ตัวอย่างเช่นหากคุณกำลังทำงานกับ JSON API คุณอาจกำหนดอินเทอร์เฟซที่ระบุสองวิธี:“ toJson” และ“ toStatusCode” สิ่งนี้จะช่วยให้คุณสามารถเขียนผู้ช่วยที่สามารถนำวัตถุใด ๆ ที่ใช้อินเทอร์เฟซนี้และแปลงเป็นการตอบสนองของ Http

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

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

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

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

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

แน่นอนว่าเป็นไปไม่ได้เสมอไป ตัวอย่างเช่นเว็บเฟรมเวิร์ก Play ให้ไลบรารี JSON ที่เป็นภาษาเฉพาะโดเมน การเปลี่ยนสิ่งนี้จะเป็นภารกิจหลักซึ่งการแทนที่การเรียกไปที่ 'Json.prettyPrint' จะเป็นเพียงส่วนน้อยมาก


1

องค์ประกอบคือเมื่อคลาสมีฟังก์ชั่นบางอย่างโดยการสร้างอินสแตนซ์คลาส (อาจเป็นภายใน) ซึ่งใช้ฟังก์ชันนี้แทนการสืบทอดจากคลาสนั้น

ตัวอย่างเช่นถ้าคุณมีคลาสที่จำลองเรือและตอนนี้คุณกำลังถูกบอกว่าเรือของคุณควรมีลานจอดเฮลิคอปเตอร์มันไม่ใช่เรื่องธรรมดาเลยที่จะได้รับเรือของคุณจากลานจอดเฮลิคอปเตอร์ (duh!) แทนคุณควรมี เรือของคุณมีชั้นเรียนลานจอดเฮลิคอปเตอร์และเปิดเผยด้วยShip.getHelipad()วิธีการบางอย่าง

ในปีที่ผ่านมา (ทศวรรษหรือมากกว่านั้น) ผู้คนเคยมองว่าการสืบทอดเป็นวิธีที่รวดเร็วและง่ายต่อการรวมฟังก์ชันการทำงานดังนั้นจึงมีตัวอย่างมากมายของชนิด "เรือที่สืบทอดจากลานจอดเฮลิคอปเตอร์" ซึ่งแน่นอนว่าอ่อนแอมาก

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

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

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

หากต้องการกลับไปที่ตัวอย่างเรือถ้าเรือของคุณต้องการนำเสนออินเทอร์เฟซสำหรับการโต้ตอบกับFloatingMachineมันจะเป็นเรื่องธรรมดากว่าที่จะได้มาจากFloatingMachineคลาสนามธรรมซึ่งอาจเป็นไปได้ว่ามาจากMachineคลาสนามธรรมอื่น

นี่คือกฎง่ายๆสำหรับคำตอบของการแต่งเทียบกับคำถามมรดก:

คลาสของฉันมีความสัมพันธ์แบบ "เป็น" กับส่วนต่อประสานที่ต้องเปิดเผยหรือไม่? ถ้าใช่ใช้การสืบทอด ถ้าไม่ใช้องค์ประกอบ

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

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