เมื่อวางแผนโปรแกรมของฉันฉันมักจะเริ่มต้นด้วยความคิดอย่าง:
ทีมฟุตบอลเป็นเพียงรายชื่อผู้เล่นฟุตบอล ดังนั้นฉันควรเป็นตัวแทนด้วย:
var football_team = new List<FootballPlayer>();การเรียงลำดับของรายการนี้แสดงถึงลำดับที่ผู้เล่นแสดงไว้ในบัญชีรายชื่อ
แต่ฉันตระหนักในภายหลังว่าทีมยังมีคุณสมบัติอื่น ๆ นอกเหนือจากรายชื่อผู้เล่นที่ต้องบันทึกไว้ ตัวอย่างเช่นคะแนนรวมที่ดำเนินการอยู่ในฤดูกาลนี้งบประมาณปัจจุบันสีสม่ำเสมอstringชื่อตัวแทนของทีม ฯลฯ
ดังนั้นฉันคิดว่า:
โอเคทีมฟุตบอลก็เหมือนกับรายการของผู้เล่น แต่นอกจากนี้ยังมีชื่อ (a
string) และคะแนนรวมทั้งหมด (anint) .NET ไม่มีคลาสสำหรับเก็บทีมฟุตบอลดังนั้นฉันจะสร้างคลาสของตัวเอง โครงสร้างที่มีอยู่ที่คล้ายกันและเกี่ยวข้องมากที่สุดคือList<FootballPlayer>ดังนั้นฉันจะสืบทอดจากมัน:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
แต่มันกลับกลายเป็นว่าแนวทางในการพูดว่าคุณไม่ควรสืบทอดมาจาก List<T>ฉันสับสนอย่างละเอียดโดยแนวทางนี้สองประการ
ทำไมจะไม่ล่ะ?
เห็นได้ชัดว่ามีการเพิ่มประสิทธิภาพอย่างใดเพื่อให้ได้ประสิทธิภาพList งั้นเหรอ ฉันจะทำให้เกิดปัญหาประสิทธิภาพการทำงานถ้าฉันขยายList? จะเกิดอะไรขึ้น
เหตุผลที่ผมเคยเห็นก็คือการที่Listให้บริการโดยไมโครซอฟท์และผมสามารถควบคุมมันไม่ได้ดังนั้นฉันไม่สามารถเปลี่ยนได้ในภายหลังหลังจากเปิดเผย "ประชาชน API" แต่ฉันพยายามเข้าใจสิ่งนี้ API สาธารณะคืออะไรและทำไมฉันจึงควรใส่ใจ หากโครงการปัจจุบันของฉันไม่ได้และไม่น่าจะมี API สาธารณะนี้ฉันจะเพิกเฉยต่อแนวทางนี้ได้อย่างปลอดภัยหรือไม่? หากฉันได้รับช่วงต่อจากนี้List และกลายเป็นว่าฉันต้องการ API สาธารณะฉันจะมีปัญหาอะไรบ้าง
ทำไมมันถึงสำคัญ รายการคือรายการ สิ่งที่อาจเปลี่ยนแปลงได้? ฉันอาจต้องการเปลี่ยนแปลงอะไร
และสุดท้ายถ้า Microsoft ไม่ต้องการให้ฉันรับช่วงต่อListทำไมพวกเขาถึงไม่ทำคลาสsealed?
ฉันควรจะใช้อะไรอีก
เห็นได้ชัดว่าสำหรับคอลเลกชันที่กำหนดเอง, ไมโครซอฟท์ได้จัดให้มีระดับที่ควรจะขยายแทนCollection Listแต่คลาสนี้เปลือยมากและไม่มีสิ่งที่มีประโยชน์มากมายเช่นAddRangeเช่น คำตอบของ jvitor83ให้เหตุผลด้านประสิทธิภาพสำหรับวิธีการเฉพาะนั้น แต่วิธีการนั้นช้าAddRangeไม่ดีกว่าไม่AddRange?
การสืบทอดจากCollectionเป็นวิธีการทำงานมากกว่าการสืบทอดจากListและฉันไม่เห็นประโยชน์ แน่นอนว่า Microsoft จะไม่บอกให้ฉันทำงานพิเศษโดยไม่มีเหตุผลดังนั้นฉันจึงอดไม่ได้ที่จะรู้สึกว่าฉันเข้าใจผิดบางอย่างและการรับมรดกCollectionไม่ใช่วิธีแก้ปัญหาที่เหมาะสมสำหรับปัญหาของฉัน
ผมเคยเห็นข้อเสนอแนะต่าง ๆ IListเช่นการดำเนินการ แค่ไม่. นี่คือโค้ดบรรทัดสำเร็จรูปหลายสิบบรรทัด
สุดท้ายบางคนแนะนำให้ห่อListในบางสิ่ง:
class FootballTeam
{
public List<FootballPlayer> Players;
}
มีสองปัญหากับสิ่งนี้:
มันทำให้รหัสของฉัน verbose โดยไม่จำเป็น ตอนนี้ผมต้องเรียกแทนเพียง
my_team.Players.Countmy_team.Countโชคดีที่มี C # ฉันสามารถกำหนดตัวจัดทำดัชนีเพื่อให้การทำดัชนีโปร่งใสและส่งต่อวิธีการทั้งหมดของภายในList... แต่นั่นคือรหัสจำนวนมาก! ฉันจะได้อะไรจากการทำงานทั้งหมดแค่ธรรมดา ๆ ก็ไม่สมเหตุสมผล ทีมฟุตบอลไม่มีรายชื่อผู้เล่น "มี" มันเป็นรายการของผู้เล่น คุณไม่พูดว่า "John McFootballer ได้เข้าร่วมกับผู้เล่นของ SomeTeam" คุณพูดว่า "John ได้เข้าร่วม SomeTeam" คุณไม่ได้เพิ่มตัวอักษรใน "ตัวอักษรของสตริง" คุณเพิ่มตัวอักษรลงในสตริง คุณไม่เพิ่มหนังสือลงในหนังสือของห้องสมุด แต่เพิ่มหนังสือลงในห้องสมุด
ฉันรู้ว่าสิ่งที่เกิดขึ้น "ภายใต้ประทุน" อาจกล่าวได้ว่าเป็น "การเพิ่ม X เข้ากับรายการภายในของ Y" แต่นี่ดูเหมือนจะเป็นวิธีคิดที่ไม่โต้ตอบเกี่ยวกับโลก
คำถามของฉัน (สรุป)
C # วิธีที่ถูกต้องในการเป็นตัวแทนของโครงสร้างข้อมูลซึ่ง "ตรรกะ" (กล่าวคือ "เพื่อจิตใจมนุษย์") เป็นเพียงlistของที่thingsมีระฆังและนกหวีดไม่กี่?
สืบทอดมาจากที่List<T>ยอมรับไม่ได้เสมอ? ยอมรับได้เมื่อไหร่? ทำไม / ทำไมไม่ โปรแกรมเมอร์ต้องพิจารณาอะไรเมื่อตัดสินใจว่าจะสืบทอดจากList<T>หรือไม่
stringจะต้องทำทุกอย่างobjectสามารถทำและอื่น ๆ

