อะไรคือความแตกต่างในทางปฏิบัติระหว่างรูปแบบของการฉีดพึ่งพา?


12

ฉันยังใหม่กับการฉีดแบบพึ่งพาและฉันมีคำถามสองสามข้อเกี่ยวกับสไตล์ที่ฉันควรใช้ในแอปพลิเคชันของฉัน ฉันเพิ่งอ่านInversion of Control Containers และรูปแบบการพึ่งพาการฉีดของ Martin Fowler แต่ฉันไม่สามารถรับความแตกต่างระหว่าง Constructor, Setter และ Interface Injection ได้

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

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


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

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

เอ่อ ... ฉันใหม่กับตัวเองดังนั้นฉันจึงไม่แน่ใจว่าฉันจะช่วยได้อย่างไร / ทำไมมันถึงถูกโหวตให้ปิด หากฉันเดาเอาว่าอาจจะไม่ใช่คำถามเฉพาะในการเขียนโปรแกรม แต่เป็นการอภิปรายมากกว่านี้

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

คำตอบ:


12

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

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

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

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

บ่อยครั้งเหตุผลเดียวที่ฉันผ่านการใช้งานสองแบบแยกกันคือการทดสอบ ในการผลิตผมอาจจะผ่านในแต่ในการทดสอบผมจะผ่านในDataRepository FakeDataRepositoryในกรณีนี้ผมมักจะให้สองก่อสร้าง: หนึ่งเดียวกับไม่มีพารามิเตอร์, และอื่น ๆ IDataRepositoryที่ยอมรับ new DataRepository()จากนั้นในคอนสตรัคกับพารามิเตอร์ที่ไม่ฉันจะห่วงโซ่การเรียกร้องให้สร้างที่สองและผ่านใน

นี่คือตัวอย่างใน C #:


public class Foo
{
  private readonly IDataRepository dataRepository;

  public Foo() : this(new DataRepository())
  {
  }

  public Foo(IDataRespository dataRepository)
  {
    this.dataRepository = dataRepository;
  }
}

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

var foo = new Foo(new DataRepository());
อย่างไรก็ตามฉันยังสามารถผ่านการใช้งานสำรองสำหรับการทดสอบ ฉันรู้ว่าด้วย DI ของ Poor Man ฉันกำลังรหัสอ้างอิงยาก แต่ก็ยอมรับได้สำหรับฉันเพราะส่วนใหญ่ฉันใช้ DI สำหรับการทดสอบ


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

1
คุณอาจไม่ต้องการใช้การฉีดคอนสตรัคเตอร์สำหรับการอ้างอิงเพิ่มเติม ฉันไม่สามารถคิดด้วยเหตุผลอื่นใดที่จะไม่ใช้
jhewlett

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

@ jhewlett - วิเศษมากฉันกำลังมองหาเทคนิคการขัดถูแบบเรียบง่ายที่ดีสำหรับการทดสอบหน่วยที่ไม่ซับซ้อนเกินกว่าที่จะแก้ปัญหาของฉัน - และฉันคิดว่านี่เป็น :)
Rocklan

2

ความแตกต่างระหว่าง Constructor และ Setter Injection นั้นได้อธิบายไว้อย่างเพียงพอแล้วดังนั้นฉันจะไม่อธิบายรายละเอียดเพิ่มเติม

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

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

  • จะช่วยให้การเริ่มต้นขี้เกียจ - ไม่จำเป็นต้องมีการพึ่งพาที่จะเริ่มต้นจนกว่าจะมีการใช้

  • ช่วยให้สามารถโหลดการอ้างอิงจากสำเนาแคชเมื่อมีอยู่หรือกำหนดค่าเริ่มต้นใหม่เมื่อไม่มี (เช่นใช้SoftReferenceใน Java)

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

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