มีหลักการอินเตอร์เฟซ“ ถามเฉพาะสิ่งที่คุณต้องการ” หรือไม่?


9

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

ตัวอย่างเช่นหากฉันมีประเภทที่สามารถลบได้มากมายฉันจะสร้างDeletableส่วนต่อประสาน:

interface Deletable {
   void delete();
}

จากนั้นฉันสามารถเขียนคลาสสามัญ:

class Deleter<T extends Deletable> {
   void delete(T t) {
      t.delete();
   }
}

ที่อื่นในรหัสฉันมักจะถามถึงความรับผิดชอบที่เล็กที่สุดที่เป็นไปได้เพื่อตอบสนองความต้องการของรหัสลูกค้า ดังนั้นถ้าฉันจะต้องลบFileก็ยังจะขอไม่ได้ DeletableFile

หลักการนี้เป็นความรู้ทั่วไปและมีชื่อยอมรับแล้วหรือไม่? มันขัดแย้งหรือไม่ มันถูกกล่าวถึงในตำราหรือไม่?


1
คลัปหลวมอาจ? หรืออินเทอร์เฟซแคบ
tdammers

คำตอบ:


16

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


4

เพื่อขยายคำตอบที่ดีมากของ Vadim ฉันจะตอบคำถาม "is it แย้ง" กับ "ไม่ไม่จริง"

โดยทั่วไปการแยกอินเทอร์เฟซเป็นสิ่งที่ดีโดยการลดจำนวนโดยรวมของ "เหตุผลในการเปลี่ยนแปลง" ของวัตถุต่าง ๆ ที่เกี่ยวข้อง หลักการหลักคือเมื่อต้องเปลี่ยนอินเตอร์เฟซที่มีหลายวิธีพูดเพื่อเพิ่มพารามิเตอร์ให้กับหนึ่งในวิธีการอินเทอร์เฟซผู้บริโภคทุกคนของอินเทอร์เฟซจะต้องได้รับการคอมไพล์ใหม่อย่างน้อยแม้ว่าพวกเขาไม่ได้ใช้วิธีที่เปลี่ยน. "แต่มันก็แค่คอมไพล์อีกครั้ง!" ฉันได้ยินคุณพูด ที่อาจเป็นจริง แต่โปรดจำไว้ว่าโดยทั่วไปสิ่งใดก็ตามที่คุณคอมไพล์ซ้ำจะต้องถูกส่งออกมาเป็นส่วนหนึ่งของซอฟต์แวร์แพทช์ไม่ว่าการเปลี่ยนแปลงที่สำคัญจะเป็นไบนารี กฎเหล่านี้ได้รับการกำหนดแนวคิดย้อนกลับไปในช่วงต้นยุค 90 เมื่อเวิร์กสเตชันเดสก์ทอปโดยเฉลี่ยมีประสิทธิภาพน้อยกว่าโทรศัพท์ในกระเป๋าของคุณ 14.4k baud dial-up เป็น blazin 'และ 3.5 "1.44MB" floppies "เป็นสื่อที่ถอดได้หลัก แม้ในยุคปัจจุบันของ 3G / 4G ผู้ใช้อินเทอร์เน็ตไร้สายมักจะมีแผนข้อมูลที่ จำกัด ดังนั้นเมื่อปล่อยการอัปเกรดไบนารีที่น้อยลงที่ต้องดาวน์โหลดก็จะยิ่งดีขึ้น

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

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

การแยกอินเตอร์เฟสควรขึ้นอยู่กับคลาสที่ขึ้นอยู่กับอินเตอร์เฟส:

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

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

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


นอกจากนี้ยังเป็นที่น่าสังเกตว่าการแยกส่วนต่อประสานอาจใช้งานได้ดีหากใช้ภาษา / ระบบ OOP ซึ่งสามารถอนุญาตให้รหัสระบุการผสมผสานที่แม่นยำของส่วนต่อประสาน แต่อย่างน้อยใน NET พวกเขาอาจทำให้เกิดอาการปวดหัวอย่างรุนแรง วิธีระบุคอลเลกชันของ "สิ่งต่าง ๆ ที่ใช้ IFoo และ IBar แต่อาจไม่มีอะไรเหมือนกัน"
supercat

พารามิเตอร์ชนิดทั่วไปสามารถกำหนดได้ด้วยเกณฑ์รวมถึงการใช้หลายอินเตอร์เฟส แต่คุณอยู่ในนิพจน์ที่ต้องการประเภทคงที่โดยทั่วไปไม่สามารถรองรับการระบุมากกว่าหนึ่ง หากมีความต้องการให้ประเภทสแตติกใช้ทั้ง IFoo และ IBar และคุณควบคุมอินเทอร์เฟซเหล่านั้นทั้งสองอาจเป็นความคิดที่ดีที่จะนำไปใช้IBaz : IFoo, IBarและจำเป็นต้องใช้แทน
KeithS

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

ตัวอย่างเช่นอาร์เรย์จะสนับสนุน ECRW รายการอาร์เรย์จะสนับสนุน ECRWIDNA รายการเธรดที่ปลอดภัยอาจสนับสนุน ECRWNA [แม้ว่าโดยทั่วไปแล้ว A จะเป็นประโยชน์สำหรับการแสดงรายการล่วงหน้าเท่านั้น] wrapper อาร์เรย์แบบอ่านอย่างเดียวอาจรองรับ ECR อินเตอร์เฟสรายการ covariant สามารถรองรับ ECRD อินเทอร์เฟซที่ไม่ใช่แบบทั่วไปสามารถให้การสนับสนุนประเภท C หรือ CD ที่ปลอดภัย ถ้า Swap เป็นตัวเลือกบางประเภทสามารถรองรับ CS แต่ไม่ใช่ D (เช่นอาร์เรย์) ในขณะที่ประเภทอื่นรองรับ CDS การพยายามกำหนดประเภทอินเตอร์เฟสที่แตกต่างกันสำหรับการผสมผสานความสามารถที่จำเป็นแต่ละอย่างนั้นเป็นฝันร้าย
supercat

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