“ ชอบการแต่งเพลงมากกว่ามรดก” - เป็นเหตุผลเดียวที่จะป้องกันการเปลี่ยนแปลงลายเซ็นได้หรือไม่?


13

หน้านี้สนับสนุนการแต่งเพลงมากกว่าการสืบทอดด้วยอาร์กิวเมนต์ต่อไปนี้ (ใช้ถ้อยคำใหม่ในคำพูดของฉัน):

การเปลี่ยนแปลงในลายเซ็นของวิธีการของซูเปอร์คลาส (ซึ่งไม่ได้ถูกแทนที่ในคลาสย่อย) ทำให้เกิดการเปลี่ยนแปลงเพิ่มเติมในหลาย ๆ สถานที่เมื่อเราใช้การสืบทอด อย่างไรก็ตามเมื่อเราใช้ Composition การเปลี่ยนแปลงเพิ่มเติมที่จำเป็นนั้นมีอยู่ในที่เดียวนั่นคือคลาสย่อย

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



1
ดูเพิ่มเติม: พูดคุยเรื่องนี้ $ {blog}
gnat

2
คำพูดไม่ได้บอกว่าเป็น "เหตุผล" เท่านั้น
Tulains Córdova

3
การจัดองค์ประกอบเกือบดีกว่าเนื่องจากการสืบทอดโดยทั่วไปจะเพิ่มความซับซ้อนการเชื่อมต่อการอ่านรหัสและลดความยืดหยุ่น แต่มีข้อยกเว้นเด่น ๆ บางครั้งคลาสเบสหรือสองคลาสก็ไม่เจ็บ นั่นเป็นเหตุผลที่ ' ชอบ ' มากกว่า ' เสมอ '
Mark Rogers

คำตอบ:


27

ฉันชอบการเปรียบเทียบดังนั้นนี่คือสิ่งหนึ่ง: คุณเคยเห็นหนึ่งในทีวีเหล่านั้นที่มีเครื่องเล่น VCR ในตัวหรือไม่? แล้วเครื่องที่มี VCR และเครื่องเล่น DVD ล่ะ? หรืออันที่มี Blu-ray, DVD และ VCR โอ้และตอนนี้ทุกคนกำลังสตรีมดังนั้นเราต้องออกแบบชุดทีวีใหม่ ...

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

การรับมรดกเป็นเหมือนทีวีที่มี VCR ในตัว หากคุณมีพฤติกรรมที่แตกต่างกัน 3 ประเภทที่คุณต้องการใช้ร่วมกันและแต่ละตัวมี 2 ตัวเลือกสำหรับการนำไปใช้คุณต้องมี 8 คลาสที่แตกต่างกันเพื่อเป็นตัวแทนของสิ่งเหล่านั้น เมื่อคุณเพิ่มตัวเลือกเพิ่มเติมตัวเลขจะระเบิด หากคุณใช้การจัดวางองค์ประกอบแทนคุณจะหลีกเลี่ยงปัญหา combinatorial และการออกแบบจะมีแนวโน้มที่จะขยายได้มากขึ้น


6
มีทีวีมากมายพร้อมเครื่องเล่น VCR และเครื่องเล่นดีวีดีที่สร้างขึ้นในช่วงปลายยุค 90 และต้นยุค 2000
JAB

@JAB และทีวี (ส่วนใหญ่) จำนวนมากที่ขายในวันนี้รองรับการสตรีมในกรณีนี้
Casey

4
@JAB และไม่มีใครสามารถขายเครื่องเล่นดีวีดีเพื่อซื้อเครื่องเล่น Bluray
Alexander - Reinstate Monica

1
@JAB ถูกต้อง คำสั่ง "คุณเคยเห็นทีวีหนึ่งในนั้นที่มีเครื่องเล่น VCR ในตัวหรือไม่?" แสดงถึงพวกเขามีอยู่
JimmyJames

4
@Casey เพราะเห็นได้ชัดว่าจะไม่มีเทคโนโลยีอื่นที่จะเข้ามาแทนที่สิ่งนี้ใช่ไหม? ฉันจะเดิมพันว่าทีวีเหล่านี้รองรับอินพุตจากอุปกรณ์ภายนอกในกรณีที่มีคนต้องการใช้อย่างอื่นโดยไม่ต้องซื้อทีวีใหม่ หรือมากกว่านั้นผู้ซื้อที่มีการศึกษาเพียงไม่กี่คนยินดีที่จะซื้อทีวีที่ไม่มีอินพุตดังกล่าว หลักฐานของฉันไม่ได้อยู่ที่วิธีการเหล่านี้ไม่มีอยู่และฉันจะไม่เรียกร้องการสืบทอดไม่มีอยู่ ประเด็นก็คือแนวทางดังกล่าวมีความยืดหยุ่นน้อยกว่าการจัดองค์ประกอบ
JimmyJames

4

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

ด้วยวิธีนี้คุณมีวัตถุบางอย่างที่ให้บริการ คุณใช้มันเป็นแบบเอกสารสำเร็จรูป (คล้ายกับเลโก้จริงๆ) เพื่อเปิดใช้งานลักษณะการทำงานอื่น ๆ (เช่นUserRegistrationServiceใช้บริการที่ได้รับจากEmailerServiceและUserRepository )

เมื่อสร้างระบบที่ใหญ่กว่าด้วยวิธีนี้ฉันใช้มรดกโดยธรรมชาติในบางกรณี ในตอนท้ายของการรับมรดกวันเป็นเครื่องมือที่มีประสิทธิภาพมากที่ควรใช้ด้วยความระมัดระวังและเฉพาะในกรณีที่เหมาะสม


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

1
@Brilliand หากคุณรู้ว่ามีการเขียนโค้ดจาวาเพียงเท่านี้ในสไตล์ที่คุณอธิบายและสยองขวัญขนาดนี้เท่านั้น ... Smalltalk แนะนำคำว่า OOP และได้รับการออกแบบรอบวัตถุที่รับข้อความ : "การคำนวณควรถูกมองว่าเป็นความสามารถที่แท้จริงของวัตถุที่สามารถเรียกใช้อย่างสม่ำเสมอโดยการส่งข้อความ" ไม่มีการกล่าวถึงข้อมูลและฟังก์ชั่นการใช้งาน ขออภัยในความคิดของฉันคุณจะเข้าใจผิดอย่างมหันต์ ถ้ามันเป็นเพียงข้อมูลและฟังก์ชั่นอย่างหนึ่งก็สามารถเขียนโครงสร้างได้อย่างมีความสุข
marstato

@Tsar น่าเสียดายแม้ว่า Java รองรับวิธีการคงที่วัฒนธรรม Java ไม่ได้
k_g

@Brilliand ใครสนใจ OOP คืออะไร "เกี่ยวกับ" สิ่งที่สำคัญคือคุณสามารถใช้มันอย่างไรและผลลัพธ์ของการใช้มันในวิธีเหล่านั้น
user253751

1
หลังจากการสนทนากับ @Tsar: คลาส Java ไม่จำเป็นต้องมีอินสแตนซ์และแน่นอนว่าคลาสเช่นUserRegistrationServiceและEmailServiceไม่ควรถูกสร้างอินสแตนซ์ - คลาสที่ไม่มีข้อมูลที่เชื่อมโยงได้ดีที่สุดในคลาสสแตติก (และเช่นนั้นไม่เกี่ยวข้องกับต้นฉบับ คำถาม). ฉันจะลบความคิดเห็นก่อนหน้าบางส่วนของฉัน แต่คำวิจารณ์ดั้งเดิมของฉันเกี่ยวกับคำตอบของมาร์ซาโตะก็คือ
Brilliand

4

"ชอบเรียงความมากกว่ามรดก" เป็นเพียงการแก้ปัญหาที่ดี

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

ฉันหวังว่าจะทำให้ประเด็นนี้ชัดเจนในโพสต์นี้

ฉันจะไม่พยายามปกป้องข้อดีของการแต่งเพลงด้วยตัวเอง ซึ่งฉันพิจารณาหัวข้อ แต่ฉันจะพูดถึงบางสถานการณ์เมื่อผู้พัฒนาอาจพิจารณาการสืบทอดที่จะดีกว่าโดยใช้การแต่งเพลง ในบันทึกย่อนั้นการสืบทอดมีข้อดีของตัวเองซึ่งฉันพิจารณาหัวข้อด้วย


ตัวอย่างยานพาหนะ

ฉันกำลังเขียนเกี่ยวกับนักพัฒนาที่พยายามทำสิ่งที่โง่เง่าเพื่อจุดประสงค์ในการเล่าเรื่อง

ขอให้เราไปแตกต่างจากตัวอย่างคลาสสิกที่บางหลักสูตร OOP ใช้ ... เรามีVehicleระดับแล้วเราได้รับมาCar, Airplane, และBalloonShip

หมายเหตุ : หากคุณต้องการแสดงตัวอย่างนี้ให้ถือว่าสิ่งเหล่านี้เป็นวัตถุประเภทหนึ่งในวิดีโอเกม

จากนั้นCarและAirplaneอาจมีรหัสทั่วไปบางอย่างเพราะทั้งคู่สามารถหมุนล้อบนพื้นดินได้ ผู้พัฒนาอาจพิจารณาสร้างคลาสตัวกลางในห่วงโซ่การสืบทอดสำหรับสิ่งนั้น แต่รหัสจริงนอกจากนี้ยังมีการใช้ร่วมกันบางอย่างระหว่างและAirplane Balloonพวกเขาสามารถพิจารณาสร้างคลาสตัวกลางอื่นในห่วงโซ่การสืบทอดสำหรับสิ่งนั้น

ดังนั้นผู้พัฒนาจะค้นหามรดกหลายรายการ ณ จุดที่นักพัฒนากำลังมองหาการสืบทอดหลายแบบการออกแบบผิดพลาดไปแล้ว

เป็นการดีกว่าหากวางโมเดลพฤติกรรมนี้เป็นอินเทอร์เฟซและการจัดองค์ประกอบดังนั้นเราจึงสามารถนำกลับมาใช้ใหม่ได้โดยไม่ต้องใช้การสืบทอดหลายคลาส ตัวอย่างเช่นหากนักพัฒนาสร้างFlyingVehiculeคลาส พวกเขาจะบอกว่านั่นAirplaneคือFlyingVehicule(การสืบทอดคลาส) แต่เราสามารถพูดAirplaneได้ว่ามีFlyingองค์ประกอบ (องค์ประกอบ) และAirplaneเป็นIFlyingVehicule(การสืบทอดส่วนต่อประสาน)

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

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

Amphibiousทุกสิ่งที่ไม่ต้องกล่าวถึง

ในความเป็นจริงเราอาจไม่ต้องการสิ่งที่ลงไปจากพื้น สตีเฟ่น Hurn มีตัวอย่างฝีปากอื่น ๆ ในบทความของเขา“โปรดปรานองค์ประกอบกว่ามรดก” ส่วน 1และส่วนที่ 2


ความสามารถในการทดแทนและการห่อหุ้ม

ควรAสืบทอดหรือเรียบเรียงB?

หากAเป็นความเชี่ยวชาญเฉพาะด้านBที่ควรทำตามหลักการทดแทนของ Liskov การสืบทอดจะเป็นไปได้แม้เป็นที่ต้องการ หากมีสถานการณ์ที่Aไม่มีการทดแทนที่ถูกต้องBเราก็ไม่ควรใช้การสืบทอด

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

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

องค์ประกอบยังมีข้อดีของการอนุญาตให้ใช้งานสวิตช์และการเยาะเย้ยทำให้สบาย

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

ในที่สุดแน่นอนมีข้อโต้แย้งว่าเราควรใช้องค์ประกอบเพื่อปกป้องชั้นผู้ปกครองเพราะมรดกแบ่ง encapsulation ของชั้นผู้ปกครอง:

การสืบทอดทำให้คลาสย่อยมีรายละเอียดเกี่ยวกับการนำไปปฏิบัติของผู้ปกครองมันมักจะกล่าวว่า

- รูปแบบการออกแบบ: องค์ประกอบของซอฟต์แวร์เชิงวัตถุที่ใช้ซ้ำได้ Gang of Four

นั่นคือคลาสผู้ปกครองที่ออกแบบมาไม่ดี นี่คือเหตุผลที่คุณควร:

ออกแบบสำหรับการสืบทอดหรือห้าม

- Java ที่มีประสิทธิภาพ, Josh Bloch


ปัญหาเรื่องโยโย่

กรณีที่องค์ประกอบช่วยก็คือYo-Yo ปัญหา นี่คือคำพูดจาก Wikipedia:

ในการพัฒนาซอฟต์แวร์ปัญหา yo-yo เป็นรูปแบบการต่อต้านที่เกิดขึ้นเมื่อโปรแกรมเมอร์ต้องอ่านและทำความเข้าใจกับโปรแกรมที่กราฟกราฟการสืบทอดมีความยาวและซับซ้อนจนโปรแกรมเมอร์ต้องพลิกระหว่างคำจำกัดความของคลาสที่แตกต่างกันเพื่อที่จะติดตาม การควบคุมการไหลของโปรแกรม

คุณสามารถแก้ไขตัวอย่างเช่น: ระดับของคุณจะไม่ได้รับมรดกจากชั้นเรียนC Bชั้นเรียนของคุณCจะมีสมาชิกประเภทหนึ่งAซึ่งอาจเป็นหรือไม่เป็นประเภทวัตถุBก็ได้ วิธีนี้คุณจะไม่ได้เขียนโปรแกรมกับรายละเอียดการใช้งานBแต่เทียบกับสัญญาที่ส่วนต่อประสาน (จาก) Aเสนอ


ตัวอย่างเคาน์เตอร์

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

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

ภาคผนวก : มีวิธีอื่น ๆ ที่สามารถอนุญาตให้ขยายวัตถุ ORM ได้ ดังนั้นฉันไม่คิดว่าการสืบทอดเป็นสิ่งจำเป็นในกรณีนี้ มันถูกกว่า.

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

นอกจากนี้หากไม่มีส่วนการเรนเดอร์ 3D นี่คือจำนวนกรอบงานวิดเจ็ตที่ทำงาน สิ่งนี้ทำให้คุณไม่ต้องกังวลเกี่ยวกับการจัดการข้อความ OS …อันที่จริงในหลาย ๆ ภาษาคุณไม่สามารถเขียนรหัสดังกล่าวได้โดยไม่ต้องมีการซ่อนพื้นเมือง ยิ่งกว่านั้นถ้าคุณต้องทำมันจะทำให้การพกพาของคุณแน่น แต่ด้วยการสืบทอดให้นักพัฒนาไม่ทำลายความเข้ากันได้ (มากเกินไป); คุณจะสามารถย้ายรหัสของคุณไปยังแพลตฟอร์มใหม่ใด ๆ ที่พวกเขาสนับสนุนในอนาคตได้อย่างง่ายดาย

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

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

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


ความคิดสุดท้าย

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

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

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


เอ่อ ... . Net framework ใช้สตรีมที่สืบทอดมาหลายประเภทเพื่อทำงานที่เกี่ยวข้องกับสตรีม มันใช้งานได้ดีอย่างไม่น่าเชื่อและใช้งานง่ายสุด ๆ ตัวอย่างของคุณไม่ดีมาก ...
ต. ส

1
@Sar "มันใช้งานง่ายสุด ๆ และต่อขยาย" คุณเคยลองทีสตรีมมาตรฐานไปยัง Debug แล้วหรือยัง? นั่นเป็นประสบการณ์เดียวของฉันที่พยายามจะขยายสายน้ำของพวกเขา มันไม่ง่ายเลย มันเป็นฝันร้ายที่จบลงที่ฉันเอาชนะทุก ๆ วิธีในชั้นเรียนอย่างชัดเจน ซ้ำซากอย่างมาก และถ้าคุณดูที่ซอร์สโค้ด. NET การเอาชนะทุกสิ่งอย่างชัดเจนนั้นเป็นวิธีที่พวกเขาทำ ดังนั้นฉันจึงไม่เชื่อว่ามันจะง่ายต่อการขยาย
jpmc26

การอ่านและการเขียนโครงสร้างจากสตรีมทำได้ดีกว่าด้วยฟังก์ชั่นฟรีหรือมัลติวิธี
user253751

@ jpmc26 ฉันขอโทษประสบการณ์ของคุณไม่ดีมาก อย่างไรก็ตามฉันไม่มีปัญหาในการใช้หรือนำสิ่งที่เกี่ยวข้องกับสตรีมไปใช้กับสิ่งต่าง ๆ อย่างไรก็ตาม
ต. Sar

3

โดยปกติแล้วแนวคิดในการขับรถของการประพันธ์แบบ Over-In-สืบทอดคือการให้ความยืดหยุ่นในการออกแบบที่มากขึ้นและไม่ลดปริมาณของรหัสที่คุณต้องเปลี่ยนเพื่อเผยแพร่การเปลี่ยนแปลง (ที่ฉันคิดว่าน่าสงสัย)

ตัวอย่างใน วิกิพีเดียให้ตัวอย่างที่ดีกว่าเกี่ยวกับพลังของวิธีการของเขา:

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


ดังนั้นนี้แสดงให้เห็นตัวอย่างองค์ประกอบใช่มั้ย? ฉันถามเพราะมันไม่ชัดเจนในบทความ
Utku

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

2

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

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

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

วันถัดไปฉันถามว่านี่คือสิ่งที่ต้องการ คุณคิดว่าเจ้านายพูดอะไร

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

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

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

ทิศทางมีประสิทธิภาพมาก ใช้มันอย่างชาญฉลาด


0

นี่คืออีกเหตุผล: ในหลายภาษา OO (ฉันคิดถึงภาษาอย่าง C ++, C # หรือ Java ที่นี่) ไม่มีวิธีใดในการเปลี่ยนคลาสของวัตถุเมื่อคุณสร้างมันขึ้นมา

สมมติว่าเรากำลังสร้างฐานข้อมูลพนักงาน เรามีฐานพนักงานที่เป็นนามธรรมและเริ่มได้รับคลาสใหม่สำหรับบทบาทเฉพาะ - วิศวกรฝ่ายรักษาความปลอดภัยพนักงานขับรถบรรทุกและอื่น ๆ แต่ละชั้นมีพฤติกรรมพิเศษสำหรับบทบาทนั้น ทุกอย่างเป็นสิ่งที่ดี.

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

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

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


หรือคุณสร้างคลาส Employee ที่มีตัวชี้ไปยัง List of Roles และแต่ละงานที่แท้จริงจะขยายบทบาท ตัวอย่างของคุณอาจถูกสร้างขึ้นเพื่อใช้มรดกในวิธีที่ดีและเหมาะสมโดยไม่ต้องทำงานมากเกินไป
T. Sar

0

การสืบทอดมีสองสิ่ง:

1) การใช้รหัสซ้ำ: สามารถทำได้โดยง่ายผ่านการจัดองค์ประกอบ และในความเป็นจริงแล้วจะประสบความสำเร็จได้ดีกว่าผ่านการจัดองค์ประกอบตามที่ดีกว่าเก็บรักษาห่อหุ้ม

2) ความแตกต่าง: สามารถทำได้ผ่าน "อินเทอร์เฟซ" (คลาสที่วิธีการทั้งหมดเป็น pure-virtual)

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

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

ในที่สุดในหลาย ๆ ภาษาการทดสอบหน่วย "องค์ประกอบ" ตามวัตถุจะง่ายกว่าการทดสอบหน่วย "การสืบทอด" ตามวัตถุโดยการแทนที่วัตถุสมาชิกด้วยวัตถุจำลอง / ทดสอบ / จำลอง


0

นั่นเป็นเหตุผลเดียวที่จะสนับสนุนการแต่งเพลงมากกว่าการสืบทอด?

Nope

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

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

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

จากนั้นฉันจะอ่านรหัสของพวกเขาเพื่อหาฟังก์ชั่น overriden หากฉันไม่เห็นสิ่งใดฉันจะจัดว่าสิ่งนั้นเป็นการใช้ในทางที่ผิด พวกเขาควรจะใช้การเรียบเรียงแทนถ้าเพียงเพื่อช่วยฉัน (และทุกคนในทีม) จากการอ่านรหัสของพวกเขา 5 นาที!

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

บทเรียนหลายคน (แม้แต่คนที่เป็นทางการ) ขอแนะนำให้คุณขยายเพื่อให้คุณสามารถรักษากรณีของชั้นเรียนของคุณเป็นกรณีของJFrame JFrameแต่ imho (และความเห็นของคนอื่น ๆ ) ก็คือนี่เป็นนิสัยที่ไม่ดีพอที่จะเข้ามา! คุณควรสร้างอินสแตนซ์JFrameและเรียกใช้ฟังก์ชันบนอินสแตนซ์นั้นแทน ไม่มีความจำเป็นที่จะต้องขยายJFrameในตัวอย่างนี้เนื่องจากคุณไม่ได้เปลี่ยนพฤติกรรมเริ่มต้นของคลาสแม่

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

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


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

1
@ jpmc26 ... ทำไมคุณต้องใช้คลาสโรงงานเพื่อสร้างตัวอย่างใหม่ของคลาส และการสืบทอดจะปรับปรุงความสามารถในการอ่านของสิ่งที่คุณกำลังอธิบายได้อย่างไร
Kevin Workman

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

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

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