สามารถฉีดได้กี่ครั้งในหนึ่งชั้นเมื่อใช้การฉีดแบบพึ่งพา


9

ฉันใช้ Unity ใน C # สำหรับการฉีดพึ่งพา แต่คำถามควรใช้กับภาษาและกรอบงานใด ๆ ที่ใช้การฉีดพึ่งพา

ฉันพยายามทำตามหลักการ SOLID ดังนั้นฉันจึงมี abstractions มากมาย แต่ตอนนี้ฉันสงสัยว่ามีวิธีปฏิบัติที่ดีที่สุดในการฉีดหนึ่งชั้นควรจะฉีดเท่าไหร่?

ตัวอย่างเช่นฉันมีพื้นที่เก็บข้อมูลที่มีการฉีด 9 ครั้ง สิ่งนี้จะยากที่จะอ่านสำหรับผู้พัฒนารายอื่นหรือไม่?

การฉีดมีความรับผิดชอบดังต่อไปนี้:

  • IDbContextFactory - สร้างบริบทสำหรับฐานข้อมูล
  • IMapper - การแมปจากเอนทิตีกับโมเดลโดเมน
  • IClock - บทคัดย่อ DateTime ตอนนี้จะช่วยในการทดสอบหน่วย
  • IPerformanceFactory - วัดเวลาดำเนินการสำหรับวิธีการเฉพาะ
  • ILog - Log4net สำหรับการบันทึก
  • ICollectionWrapperFactory - สร้างคอลเลกชัน (ที่ขยาย IEnumerable)
  • IQueryFilterFactory - สร้างเคียวรีตามอินพุตที่จะเคียวรี db
  • IIdentityHelper - ดึงผู้ใช้ที่เข้าสู่ระบบ
  • IFaultFactory - สร้าง FaultExceptions ที่แตกต่างกัน (ฉันใช้ WCF)

ฉันไม่ได้ผิดหวังกับวิธีการมอบหมายความรับผิดชอบ แต่ฉันเริ่มกังวลเกี่ยวกับความสามารถในการอ่าน

ดังนั้นคำถามของฉัน:

มีการ จำกัด จำนวนการฉีดที่ชั้นควรมีหรือไม่? และถ้าเป็นเช่นนั้นจะหลีกเลี่ยงได้อย่างไร?

การฉีดจำนวนมากจำกัดความสามารถในการอ่านหรือไม่หรือปรับปรุงได้จริงหรือไม่


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

3
มีการยอมรับอาร์กิวเมนต์ตัวสร้างจำนวนเท่าใด IoC ไม่ได้เปลี่ยนแปลงสิ่งนั้น
Telastyn

ทำไมผู้คนถึงต้องการขีด จำกัด แบบสัมบูรณ์เสมอ
Marjan Venema

1
@Telastyn: ไม่จำเป็นต้อง การเปลี่ยนแปลงของ IoC คือแทนที่การพึ่งพาคลาสสแตติก / ซิงเกิล / ตัวแปรส่วนกลางการพึ่งพาทั้งหมดจะถูกรวมศูนย์และ "มองเห็นได้" มากกว่า
Arseni Mourzenko

@MarjanVenema: เพราะมันทำให้ชีวิตง่ายขึ้นมาก หากคุณรู้ว่า LOC สูงสุดต่อวิธีหรือจำนวนสูงสุดของวิธีในคลาสหรือจำนวนตัวแปรสูงสุดในวิธีการและนี่เป็นสิ่งเดียวที่สำคัญมันกลายเป็นเรื่องง่ายที่จะมีคุณสมบัติรหัสดีหรือไม่ดีเช่น เช่นเดียวกับ“ แก้ไข” รหัสที่ไม่ดี นี่เป็นเรื่องน่าเสียดายที่ชีวิตจริงมีความซับซ้อนมากกว่านั้นและตัวชี้วัดส่วนใหญ่ไม่เกี่ยวข้องเลย
Arseni Mourzenko

คำตอบ:


11

การพึ่งพามากเกินไปอาจบ่งบอกว่าคลาสตัวเองกำลังทำมากเกินไป เพื่อตรวจสอบว่ามันไม่ได้ทำมากเกินไป:

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

  • ดูประเภทของการอ้างอิง อันไหนเป็นโดเมนเฉพาะและอันไหนเป็น“ ทั่วโลก” ตัวอย่างเช่นฉันจะไม่พิจารณาILogในระดับเดียวกับIQueryFilterFactory: คนแรกจะมีอยู่ในชั้นเรียนธุรกิจส่วนใหญ่อย่างไรก็ตามถ้าพวกเขากำลังใช้การบันทึก ในทางกลับกันหากคุณพบว่ามีการพึ่งพาโดเมนจำนวนมากสิ่งนี้อาจบ่งบอกว่าชั้นเรียนกำลังทำมากเกินไป

  • ดูการพึ่งพาซึ่งสามารถถูกแทนที่ด้วยค่า

    IClock - บทคัดย่อ DateTime ตอนนี้จะช่วยในการทดสอบหน่วย

    สิ่งนี้สามารถถูกแทนที่ได้อย่างง่ายดายโดยDateTime.Nowถูกส่งโดยตรงไปยังวิธีการที่จำเป็นต้องรู้เวลาปัจจุบัน

โดยการดูการพึ่งพาที่แท้จริงฉันไม่เห็นอะไรเลยซึ่งบ่งบอกถึงสิ่งที่ไม่ดีเกิดขึ้น:

  • IDbContextFactory - สร้างบริบทสำหรับฐานข้อมูล

    ตกลงเราอาจอยู่ในเลเยอร์ธุรกิจที่คลาสมีปฏิสัมพันธ์กับเลเยอร์การเข้าถึงข้อมูล ดูดี

  • IMapper - การแมปจากเอนทิตีกับโมเดลโดเมน

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

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

  • IClock - บทคัดย่อ DateTime ตอนนี้จะช่วยในการทดสอบหน่วย

    มันอาจจะไม่มีประโยชน์มากที่จะมีส่วนต่อประสาน (และคลาส) แยกต่างหากเพื่อให้ได้เวลาปัจจุบัน ฉันเพียงแค่ส่งผ่านDateTime.Nowไปยังวิธีการที่ต้องการเวลาปัจจุบัน

    ชั้นเรียนที่แยกต่างหากอาจสมเหตุสมผลถ้ามีข้อมูลอื่น ๆ เช่นเขตเวลาหรือช่วงวันที่เป็นต้น

  • IPerformanceFactory - วัดเวลาดำเนินการสำหรับวิธีการเฉพาะ

    ดูประเด็นต่อไป

  • ILog - Log4net สำหรับการบันทึก

    ฟังก์ชันการทำงานของ transcendant ดังกล่าวควรเป็นของเฟรมเวิร์กและไลบรารี่ที่แท้จริงควรสามารถใช้แทนกันได้และสามารถกำหนดค่าได้ที่รันไทม์ (เช่นผ่าน app.config ใน. NET)

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

    หากห้องสมุดมีความซับซ้อนเกินกว่าที่จะใช้รูปแบบซุ้มทำให้รู้สึก

  • ICollectionWrapperFactory - สร้างคอลเลกชัน (ที่ขยาย IEnumerable)

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

  • IQueryFilterFactory - สร้างเคียวรีตามอินพุตที่จะเคียวรี db

    ทำไมจึงไม่อยู่ในชั้นการเข้าถึงข้อมูล ทำไมถึงมีFilterชื่อ?

  • IIdentityHelper - ดึงผู้ใช้ที่เข้าสู่ระบบ

    ฉันไม่แน่ใจว่าทำไมมีHelperคำต่อท้าย ในทุกกรณีส่วนต่อท้ายอื่น ๆ จะไม่ชัดเจนเป็นพิเศษเช่นกัน ( IIdentityManager?)

    อย่างไรก็ตามมันเหมาะสมอย่างยิ่งที่จะมีการพึ่งพาที่นี่

  • IFaultFactory - สร้าง FaultExceptions ที่แตกต่างกัน (ฉันใช้ WCF)

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

    ฉันจะพยายามที่จะ refactor throw new FaultException(...)ที่เป็นที่เรียบง่าย หากข้อมูลทั่วโลกบางส่วนควรถูกเพิ่มลงในข้อยกเว้นทั้งหมดก่อนที่จะเผยแพร่ไปยังไคลเอนต์ WCF อาจมีกลไกที่คุณตรวจจับข้อยกเว้นที่ไม่สามารถจัดการได้และสามารถเปลี่ยนแปลงได้

มีการ จำกัด จำนวนการฉีดที่ชั้นควรมีหรือไม่? และถ้าเป็นเช่นนั้นจะหลีกเลี่ยงได้อย่างไร?

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

การฉีดจำนวนมากจำกัดความสามารถในการอ่านหรือไม่หรือปรับปรุงได้จริงหรือไม่

การพึ่งพาจำนวนมากทำให้ตรรกะยากขึ้น ถ้าลอจิกยากที่จะติดตามคลาสอาจทำมากเกินไปและควรแยก


ขอบคุณสำหรับความคิดเห็นและเวลาของคุณ ส่วนใหญ่เกี่ยวกับ FaultFactory ซึ่งจะถูกย้ายไปที่ WCF-logic แทน ฉันจะเก็บ IClock ไว้เพราะมันเป็นเครื่องมือช่วยชีวิตเมื่อ TDD-ing แอปพลิเคชัน มีหลายครั้งเมื่อคุณต้องการตรวจสอบให้แน่ใจว่ามีการตั้งค่าเฉพาะตามเวลาที่กำหนด จากนั้น DateTime ตอนนี้จะไม่พอเพียงเพราะไม่ได้ล้อเลียน
smoksnes

7

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

  • กวาดปัญหาใต้พรมปูพื้นโดยเริ่มใหม่ขึ้นต่อกันแทน
  • พิจารณาการออกแบบของเรา บางทีการพึ่งพาอาศัยกันบางครั้งมักจะมาด้วยกันและควรซ่อนอยู่หลังสิ่งที่เป็นนามธรรมอื่น ๆ บางทีคลาสของคุณควรแบ่งออกเป็น 2 บางทีมันควรจะประกอบด้วยหลายคลาสที่แต่ละคลาสย่อยต้องมีการพึ่งพาเล็กน้อย

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

ในการตอบคำถามสุดท้ายของคุณ:

  • มีขีด จำกัด สูงสุดของการอ้างอิงจำนวนชั้นควรมี?

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

  • การฉีดแบบพึ่งพาปรับปรุงหรือทำร้ายการอ่านได้หรือไม่?

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

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


1
ข้อเสนอแนะที่ดี ขอบคุณ. ใช่ขีด จำกัด บนคือ "มากเกินไป" - ยอดเยี่ยมและจริงมาก
smoksnes

3

ตามที่สตีฟ McConnel ผู้เขียน "รหัสสมบูรณ์" แพร่หลายกฎของหัวแม่มือคือมากกว่า 7 เป็นกลิ่นรหัสที่เจ็บบำรุงรักษา โดยส่วนตัวฉันคิดว่าตัวเลขส่วนใหญ่จะต่ำกว่า แต่การทำ DI อย่างเหมาะสมจะส่งผลให้มีการพึ่งพาจำนวนมากในการฉีดเมื่อคุณอยู่ใกล้กับ Composition Root นี่เป็นเรื่องปกติและคาดหวัง เป็นหนึ่งในเหตุผลที่คอนเทนเนอร์ IoC เป็นสิ่งที่มีประโยชน์และคุ้มค่ากับความซับซ้อนที่เพิ่มเข้ากับโครงการ

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

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