ความแตกต่างระหว่าง Dependency Injection (DI) และ Inversion of Control (IOC)


117

ฉันได้เห็นการอ้างอิงจำนวนมากของ Dependency Injection (DI) & Inversion Of Control (IOC) แต่ฉันไม่รู้จริง ๆ ว่ามีความแตกต่างระหว่างพวกเขาหรือไม่

ฉันต้องการเริ่มใช้หนึ่งหรือทั้งสองอย่าง แต่ฉันสับสนเล็กน้อยว่ามันแตกต่างกันอย่างไร


การผกผันของการควบคุมมักจะหมายถึง "ภาชนะบรรจุ" ในขณะที่การพึ่งพาการฉีดหมายถึงรูปแบบที่เกิดขึ้นจริง แต่พวกเขาไปจับมือกัน ฉันอยากจะแนะนำให้อ่านบทความของ Martin Fowlerเพื่อรับการจัดการในหัวข้อ
Ben Hoffstein

การพึ่งพาการฉีดเป็นสิ่งที่คุณทำซึ่งนำไปสู่โครงสร้างคำสั่งที่เรียกว่า Inversion of Control มีการเชื่อมโยงโดยเนื้อแท้

2
DI เป็นรูปแบบของ IoC ผมให้คำอธิบายรายละเอียดสวย DI และ IoC ในคำตอบนี้

2
ฉันบอกว่า DI เป็นกรณีพิเศษของ IOC การควบคุมแบบดั้งเดิมไปที่โมดูล -> โมดูลคำขอจากผู้จัดการโมดูลใน DI มันกลับไปที่ผู้จัดการโมดูล -> รับการอ้างอิงที่ร้องขอจากโมดูล
Rafał Dowgird

ดังนั้นในคำอื่น ๆ โดยทั่วไป IoC คือการใช้ DI ฉันได้รับที่ถูกต้องหรือไม่
dance2die

คำตอบ:


53

คำนิยาม

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

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

ทำงานร่วมกัน

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

ตัวอย่าง

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

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

ในขณะนั้นมีการใช้วิธีการจากโรงงานเพื่อสร้างปลั๊กอินโดยใช้ข้อมูลการกำหนดค่าการสะท้อนและวัตถุ Activator (อย่างน้อยใน. NET) วันนี้มีเครื่องมือMEFสำหรับหนึ่งตัวที่อนุญาตให้มีตัวเลือกที่กว้างขึ้นเมื่อฉีดการพึ่งพารวมถึงความสามารถในกรอบแอปพลิเคชันเพื่อรับรายการปลั๊กอินเป็นการพึ่งพา

สรุป

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


3
ไม่ IoC เป็นแนวคิดที่เก่ากว่าและเป็นอิสระจาก DI (ซึ่งไม่ได้ขึ้นอยู่กับ IoC) ตัวอย่างเช่นใช้ Struts framework (Java): มันอาศัย IoC เป็นอย่างมาก แต่ไม่ได้ใช้ DI
Rogério

1
@ Rogério - คุณพูดดีว่าทั้งสองแนวคิดไม่ต้องการซึ่งกันและกัน ฉันปรับปรุงคำตอบของฉันเพื่อชี้แจงว่าแล้วอธิบายอย่างรวดเร็วว่ากรอบงานบางอย่างใช้ร่วมกันเพื่ออนุญาตให้ใช้โค้ดที่มีการเชื่อมโยงกันอย่างหลวม ๆ
Chuck

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

0

บทความที่ดีที่จะเข้าใจ IOC และ DI http://martinfowler.com/articles/injection.html

IOC (การผกผันของการควบคุม)

IOC หมายถึง

  1. การเข้ารหัสไปยังส่วนต่อประสาน (องค์ประกอบหนึ่งควรขึ้นอยู่กับส่วนต่อประสานของส่วนประกอบอื่นและไม่ได้อยู่ใน impl) และเช่น

    interface iComp_2 {...}
    
    class Comp_1 {
        iComp_2 c2 = ….;
    }
    
  2. ลบรหัสเฉพาะการใช้งานส่วนประกอบเช่น

    Comp_1 {
        iComp_2 c2 = getComp_2_Impl(); // not new Comp_2_Impl();
    }
    

IOC สามารถทำได้โดยหนึ่งในสิ่งต่อไปนี้:

1. DI (การพึ่งพาการฉีด)

3 types of DI

1.1 Constructor Injection

1.2 Setter Injection

1.3 Interface Injection

2. ผู้ให้บริการ

ภาชนะ DI (Dependency Injection)

การกำหนดเวลารันไทม์แบบไทม์และไม่รวมเวลา: กำหนดตอนรันไทม์ซึ่งการใช้งานอินเทอร์เฟซที่เป็นรูปธรรมที่จะใช้ขึ้นอยู่กับไฟล์ปรับแต่งบางไฟล์ (ดังนั้นในเวลาคอมไพล์เราไม่ทราบว่าจะใช้ impl ใด . มันเป็นการนำไปปฏิบัติที่ความสัมพันธ์ที่เป็นรูปธรรมระหว่างโมดูลที่แตกต่างกันจะถูกตัดสินใจที่ "รันไทม์"

การสร้างอินสแตนซ์ของ impl หลังจากการฉีดพึ่งพา: หลังจากกำหนด impl แล้วมันจะสร้างอินสแตนซ์โดยเริ่มจากการสร้างการอ้างอิงทั้งหมด (ที่ระบุในไฟล์ config) ก่อนแล้วจึงฉีดการพึ่งพาเหล่านั้นลงใน impl

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


6
คุณอ่านบทความ "การฉีด" จริงๆหรือ IOC ไม่ได้หมายถึงสิ่งที่คำตอบนี้ไม่ได้เลย
Rogério

-3

ฉันจะบอกว่า "Inversion of Control" เป็นวิธีการออกแบบระบบที่โมดูลทั้งหมดมีความคิดของหน่วยงานที่เป็นนามธรรม

และ "การพึ่งพาการฉีด" คือการดำเนินการที่ความสัมพันธ์ที่เป็นรูปธรรมระหว่างโมดูลที่แตกต่างกันจะถูกตัดสินใจที่ "เวลาทำงาน"


-4

การผกผันของการควบคุมเป็นแนวคิดทั่วไปในภาษาที่ใช้งานได้มักจะใช้ความต่อเนื่อง นี่ให้คุณเขียน API โดยที่ทั้งสองฝั่งเป็น 'ผู้โทร' และไม่มี 'callee' ในที่อื่น ๆ สภาพแวดล้อมที่นิ่งกว่าคุณไม่มีความสามารถนี้ดังนั้นคุณต้องแฮ็คนี้เพื่อแทรกคำแนะนำในโฟลว์การควบคุม

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