มีความแตกต่างเล็กน้อยระหว่าง Java และ C # ที่เกี่ยวข้องที่นี่ ใน Java สมาชิกทุกคนจะเป็นเสมือนโดยค่าเริ่มต้น ใน C # สมาชิกทุกคนจะถูกปิดผนึกตามค่าเริ่มต้น - ยกเว้นสมาชิกส่วนต่อประสาน
สมมติฐานที่มีอิทธิพลต่อแนวทางนี้ - ใน Java ทุกประเภทสาธารณะควรได้รับการพิจารณาว่าไม่เป็นไปตามหลักการทดแทนของ Liskov [1] หากคุณมีเพียงหนึ่งในการดำเนินงานที่คุณจะชื่อชั้นParser
; หากคุณพบว่าคุณต้องการการนำไปใช้งานที่หลากหลายคุณเพียงแค่เปลี่ยนคลาสเป็นอินเทอร์เฟซที่มีชื่อเดียวกัน
ใน C # สมมติฐานหลักคือเมื่อคุณได้รับคลาส (ชื่อไม่ได้ขึ้นต้นด้วยI
) นั่นคือคลาสที่คุณต้องการ โปรดทราบว่านี่ไม่มีความถูกต้อง 100% - ตัวอย่างเคาน์เตอร์ทั่วไปจะเป็นคลาสเช่นStream
(ซึ่งจริงๆแล้วควรเป็นอินเทอร์เฟซหรืออินเทอร์เฟซสองสามอย่าง) และทุกคนมีแนวทางและภูมิหลังจากภาษาอื่น ๆ นอกจากนี้ยังมีข้อยกเว้นอื่น ๆ เช่นBase
คำต่อท้ายที่ใช้กันอย่างแพร่หลายเพื่อแสดงคลาสนามธรรม - เช่นเดียวกับอินเทอร์เฟซคุณรู้ว่าประเภทนั้นควรเป็น polymorphic
นอกจากนี้ยังมีคุณสมบัติการใช้งานที่ดีในการทิ้งชื่อที่ไม่ใช่ I-prefixed ไว้สำหรับฟังก์ชั่นที่เกี่ยวข้องกับส่วนต่อประสานนั้นโดยไม่ต้องหันกลับไปใช้ส่วนต่อประสานกับคลาสนามธรรม (ซึ่งอาจเจ็บเนื่องจากไม่มีคลาสหลายสืบทอดใน C #) สิ่งนี้ได้รับความนิยมจาก LINQ ซึ่งใช้IEnumerable<T>
เป็นอินเตอร์เฟสและEnumerable
เป็นที่เก็บของวิธีการที่ใช้กับอินเตอร์เฟสนั้น สิ่งนี้ไม่จำเป็นใน Java ซึ่งอินเตอร์เฟสสามารถมีวิธีการใช้งานได้เช่นกัน
ในท้ายที่สุดI
คำนำหน้าใช้กันอย่างแพร่หลายในโลก C # และโดยการขยายโลก. NET (เนื่องจากรหัส. NET ส่วนใหญ่เขียนด้วยภาษา C # จึงเหมาะสมที่จะปฏิบัติตามแนวทาง C # สำหรับอินเทอร์เฟซสาธารณะส่วนใหญ่) ซึ่งหมายความว่าคุณจะทำงานกับไลบรารีและรหัสที่เป็นไปตามสัญกรณ์นี้อย่างแน่นอนและมันก็เหมาะสมที่จะนำธรรมเนียมปฏิบัติมาใช้เพื่อป้องกันความสับสนที่ไม่จำเป็น - การที่ไม่ใช้คำนำหน้าจะทำให้รหัสของคุณดีขึ้น :)
ฉันคิดว่าการให้เหตุผลของลุงบ็อบเป็นเช่นนี้:
IBanana
เป็นแนวคิดที่เป็นนามธรรมของกล้วย หากสามารถมีคลาสการใช้งานใด ๆ ที่จะไม่มีชื่อที่ดีไปกว่าBanana
สิ่งที่เป็นนามธรรมนั้นไม่มีความหมายโดยสิ้นเชิงและคุณควรจะทิ้งอินเตอร์เฟสและใช้คลาส หากมีชื่อที่ดีกว่า (พูดLongBanana
หรือAppleBanana
) ไม่มีเหตุผลที่จะไม่ใช้Banana
เป็นชื่อของอินเทอร์เฟซ ดังนั้นการใช้I
คำนำหน้าหมายถึงคุณมีสิ่งที่เป็นนามธรรมที่ไร้ประโยชน์ซึ่งทำให้โค้ดยากที่จะเข้าใจโดยไม่มีประโยชน์ และเนื่องจาก OOP ที่เข้มงวดจะให้คุณใส่รหัสกับส่วนต่อประสานเสมอสถานที่เดียวที่คุณไม่เห็นI
คำนำหน้าของประเภทจะอยู่บนตัวสร้าง - เสียงไม่มีจุดหมาย
หากคุณใช้สิ่งนี้กับIParser
อินเทอร์เฟซตัวอย่างคุณจะเห็นได้อย่างชัดเจนว่าสิ่งที่เป็นนามธรรมนั้นอยู่ในอาณาเขต "ไร้ความหมาย" ไม่ว่าจะมีอะไรบางอย่างที่เฉพาะเจาะจงเกี่ยวกับการดำเนินงานที่เป็นรูปธรรมของตัวแยกวิเคราะห์ (เช่นJsonParser
, XmlParser
, ... ) หรือคุณก็ควรจะใช้ในชั้นเรียน ไม่มีสิ่งเช่น "การใช้งานเริ่มต้น" (แม้ว่าในบางสภาพแวดล้อมการทำเช่นนี้จะสมเหตุสมผล - โดยเฉพาะอย่างยิ่ง COM) ไม่ว่าจะมีการใช้งานที่เฉพาะเจาะจงหรือคุณต้องการระดับนามธรรมหรือวิธีการขยายสำหรับ "ค่าเริ่มต้น" อย่างไรก็ตามใน C # ยกเว้นว่า codebase ของคุณละเว้นI
-prefix ไว้ให้เก็บไว้ เพียงจดบันทึกทุกครั้งที่คุณเห็นรหัสเช่นclass Something: ISomething
- หมายความว่าบางคนไม่เก่งในการติดตาม YAGNI และสร้าง abstractions ที่สมเหตุสมผล
[1] - ในทางเทคนิคแล้วนี่ไม่ได้กล่าวถึงเฉพาะในกระดาษของ Liskov แต่เป็นหนึ่งในรากฐานของกระดาษ OOP ดั้งเดิมและในการอ่านของฉันใน Liskov เธอไม่ได้ท้าทายสิ่งนี้ ในการตีความที่เข้มงวดน้อยกว่า (ภาษาที่ใช้โดยภาษา OOP ส่วนใหญ่) นี่หมายความว่ารหัสใด ๆ ที่ใช้ประเภทสาธารณะที่มีไว้สำหรับการทดแทน