ทำไมการผกผันของการควบคุมจึงตั้งชื่อแบบนั้น?


98

คำinvertหรือcontrolไม่ได้ใช้เลยเพื่อกำหนด Inversion of Control ในคำจำกัดความที่ฉันเคยเห็น

คำนิยาม

วิกิพีเดีย

การผกผันของการควบคุม (IoC) เป็นเทคนิคการเขียนโปรแกรมแสดงไว้ที่นี่ในแง่ของการเขียนโปรแกรมเชิงวัตถุซึ่งการเชื่อมต่อวัตถุถูกผูกไว้ในเวลาทำงานโดยวัตถุประกอบและโดยทั่วไปจะไม่รู้จักในเวลารวบรวมโดยใช้การวิเคราะห์แบบคงที่ ~ http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

การผกผันของการควบคุมเป็นรูปแบบทั่วไปในชุมชน Java ที่ช่วยให้สายไฟภาชนะบรรจุที่มีน้ำหนักเบาหรือประกอบชิ้นส่วนจากโครงการที่แตกต่างกันในการประยุกต์ใช้เหนียว ~ อิงจาก http://www.martinfowler.com/articles/inject.html (reworded)


แล้วทำไม Inversion of Control ถึงชื่อว่า Inversion of Control? การควบคุมแบบใดที่กลับด้านและเกิดอะไรขึ้น มีวิธีกำหนด Inversion of Control โดยใช้คำศัพท์: กลับหัวและควบคุม ?


22
อุปกรณ์ประกอบฉากสำหรับผู้ที่สามารถอธิบายได้เป็นภาษาอังกฤษ
Robert Harvey

2
หากคำจำกัดความใช้คำที่กำหนดนั่นจะเป็นความล้มเหลวของพจนานุกรม ตรรกะที่คล้ายกันนำไปใช้ที่นี่
Izkata

2
ดูเพิ่มเติมที่ StackOverflow: Inversion of Control คืออะไร
Izkata

2
@Izkata เป็นเรื่องปกติมากสำหรับพจนานุกรมที่จะกำหนดวลีในแง่ของคำศัพท์หรือวลีที่มีความหมายเหมือนกัน เช่น: พลังแห่งธรรมชาตินิยามใช้คำว่าแรงและธรรมชาติในความหมายของมันหรือข้อกำหนดในการให้บริการใช้คำว่ากฎและบริการที่กฎมีความหมายเหมือนกันกับข้อกำหนด
Korey Hinton

3
ฉันชอบที่จะใช้คำว่า "การพึ่งพาอัตโนมัติ" หรือ ADI แทน IoC ด้วยเหตุผลนี้ ฟาวเลอร์เองกล่าวว่ากระบวนทัศน์ในปัจจุบันส่วนใหญ่ในการเขียนโปรแกรมมี "ผกผันของการควบคุม" บางคำที่ถูกกำหนดโดยทั่วไปว่า "การ relenquishing ของการกำหนดรหัสที่จะดำเนินการและเวลาที่ควรจะดำเนินการกับภายนอก ระบบควบคุมเมื่อมีการกำหนดแบบดั้งเดิมโดยโปรแกรมเอง " ทุกอย่างตั้งแต่การขัดจังหวะฮาร์ดแวร์ไปจนถึงการเขียนโปรแกรมที่ขับเคลื่อนด้วยเหตุการณ์ไปจนถึงเครื่องเสมือนและการทำงานมัลติทาสก์ที่เกิดขึ้นกับ IoC
KeithS

คำตอบ:


67

สมมติว่าคุณมีคลาส "พื้นที่เก็บข้อมูล" บางส่วนและพื้นที่เก็บข้อมูลนั้นรับผิดชอบการส่งข้อมูลให้คุณจากแหล่งข้อมูล

ที่เก็บสามารถสร้างการเชื่อมต่อกับแหล่งข้อมูลด้วยตัวเอง แต่ถ้ามันอนุญาตให้คุณผ่านการเชื่อมต่อกับแหล่งข้อมูลผ่าน Constructor ของที่เก็บ

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

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

Martin Fowler แนะนำให้ใช้คำว่า "Dependency Injection" เพื่ออธิบาย Inversion of Control ชนิดนี้เนื่องจาก Inversion of Control ในฐานะที่เป็นแนวคิดสามารถนำไปใช้ได้อย่างกว้างขวางมากกว่าเพียงแค่การฉีดขึ้นกับวิธีการสร้าง


3
นี่คือตัวอย่างของการฉีดพึ่งพา แต่การฉีดพึ่งพาเป็นเพียงส่วนหนึ่งของการผกผันของการควบคุม มีสิ่งอื่น ๆ ที่ไม่เกี่ยวข้องกับการฉีดขึ้นอยู่กับว่าฝึกผกผันของการควบคุม
dsw88

1
@ mustang2009cobra: ขอบคุณ ตัวอย่างคือสิ่งที่ฉันเป็นหลังจากไม่ใช่แคตตาล็อกที่ครอบคลุมของอินสแตนซ์ที่มันเกิดขึ้นและคำว่า "Inversion of Control" มีความสัมพันธ์อย่างใกล้ชิดกับ DI ไม่ใช่การส่งข้อความหรือแนวคิดอื่น ๆ ที่คล้ายคลึงกัน
Robert Harvey

True, การพึ่งพาอาศัยกันเป็นตัวอย่างที่แพร่หลายที่สุดของ IoC ดังนั้นตัวอย่างของ DI จึงเหมาะสมที่สุด บางทีการเปลี่ยนแปลงเล็กน้อยในคำตอบของคุณระบุว่านี่เป็นตัวอย่าง DI ซึ่งเป็น IoC ที่โดดเด่นที่สุด?
dsw88

1
นี่คือสิ่งที่ฉันกำลังมองหา! ตัวอย่างและคำจำกัดความจำนวนมากของ IoC ไม่ได้ระบุอย่างชัดเจนถึงสิ่งที่ควบคุมกลับด้าน ฉันรู้ว่าสามารถมี IoC มากกว่าการฉีดพึ่งพา แต่ตอนนี้บางสิ่งบางอย่างถูกคลิกในสมองของฉัน ขอบคุณ!
Korey Hinton

79

ฉันไม่คิดว่าทุกคนสามารถอธิบายได้ดีกว่ามาร์ตินฟาวเลอร์ไม่ต่อไปลงบทความที่คุณเชื่อมโยงกับ

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

ดังที่เขาอธิบายในย่อหน้าข้างต้นว่านี่ไม่เหมือนกันกับเหตุผลที่คำว่า "การควบคุมการผกผัน" มีต้นกำเนิด

เมื่อคอนเทนเนอร์เหล่านี้พูดถึงว่ามันมีประโยชน์อย่างไรเพราะมันใช้ "Inversion of Control" ฉันจบลงด้วยความงงมาก ความผกผันของการควบคุมเป็นลักษณะทั่วไปของเฟรมเวิร์กดังนั้นการบอกว่าภาชนะบรรจุที่มีน้ำหนักเบาเหล่านี้เป็นพิเศษเพราะพวกเขาใช้การควบคุมแบบผกผันก็เหมือนกับการบอกว่ารถของฉันมีความพิเศษเพราะมันมีล้อ

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

ซึ่งเป็นเหตุผลที่เขาไปเหรียญคำว่า "การพึ่งพาการฉีด" เพื่อให้ครอบคลุมการใช้งานเฉพาะของ Inversion of Control

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

เพื่อชี้แจงเล็กน้อย: Inversion of Control หมายถึงสิ่งใด ๆ ที่กลับโครงสร้างการควบคุมของโปรแกรมจากการออกแบบขั้นตอนแบบดั้งเดิม

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

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

Fowler และคนอื่น ๆ ตัดสินใจว่าคำว่า Inversion of Control ครอบคลุมเทคนิคมากเกินไปและเราต้องการคำศัพท์ใหม่สำหรับตัวอย่างเฉพาะของการสร้างอินสแตนซ์ของวัตถุ (Dependency Injection) แต่เมื่อถึงเวลาที่ทำข้อตกลงวลี "IoC Container "ถอดออกแล้ว

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


4
ปกติแล้วฉันจะไม่ลงคะแนนมากนัก แต่นี่เป็นคำตอบที่ดีมาก 1 คะแนนจะไม่เพียงพอ :(
RJD22

1
คำตอบนี้ตอบคำถามทั้งหมดของ IoC และ DI confusions อย่างแท้จริง
Ali Umair

32

ต่อไปนี้เป็นโปรแกรมการควบคุม "ปกติ" ตามปกติ:

  • เรียกใช้คำสั่งตามลำดับ
  • คุณรักษาการควบคุมโฟลว์ควบคุมของโปรแกรม

การผกผันของการควบคุม "กลับ" ที่ควบคุมการไหลหมายความว่ามันพลิกมันบนหัว

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

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

ตัวอย่างทั่วไปของสิ่งนี้คือเว็บเฟรมเวิร์กเช่น Rails คุณกำหนดตัวควบคุม แต่คุณไม่ได้ตัดสินใจจริง ๆ เมื่อมีคนเรียก Rails เรียกพวกเขาเมื่อมันตัดสินใจว่ามีความต้องการ


19
[ใส่ข้อผูกมัด "ในโซเวียต" ตลกที่นี่]
Robert Harvey

2
ล้อเล่นกันสิ่งที่ฉันคิดว่าคุณกำลังอธิบายเป็นเหมือนการส่งข้อความซึ่งเป็นแก่นของ OO มานานหลายทศวรรษ
Robert Harvey

3
@JimmyHoffa - นี่คือไม่ผิดเลย - ดูที่นี่ การผกผันของการควบคุมเป็นแนวคิดที่กว้างกว่าการสร้างการพึ่งพาและการฉีดการพึ่งพาเป็นเพียงรูปแบบหนึ่งของ IoC
Lee

7
@ JimmyHoffa: ฉันไม่เห็นด้วย นี่เป็นคำจำกัดความที่ถูกต้องของ Inversion of Control เช่นเดียวกับคำตอบของคุณหรือ Robert's ซึ่งเป็นสิ่งที่สับสนอย่างยิ่งที่ฟาวเลอร์อธิบายเมื่อสร้างวลีการพึ่งพาการฉีด (ซึ่งเป็นสิ่งที่คุณกำลังเรียก IoC)
pdr

5
ฉันเห็นด้วยกับคำสั่งนี้โดย @pdr: "Inversion of Control หมายถึงสิ่งใดก็ตามที่กลับโครงสร้างการควบคุมของโปรแกรมจากการออกแบบขั้นตอนแบบดั้งเดิม" นั่นคือสิ่งที่ฉันอธิบายและนั่นเป็นสิ่งที่ตรงกันข้ามกับการควบคุม การพึ่งพาการฉีดเป็นรูปแบบหนึ่งของ IoC แต่ไม่ใช่สิ่งเดียวที่ปฏิบัติ IoC
dsw88

13

มันเกี่ยวกับผู้ควบคุมการสร้างอินสแตนซ์ของการพึ่งพา

ตามเนื้อผ้าเมื่อคลาส / วิธีการจำเป็นต้องใช้คลาสอื่น (การอ้างอิง) มันจะถูกยกตัวอย่างโดยคลาส / วิธีการโดยตรง มันควบคุมการพึ่งพา

ด้วย Inversion of Control (IoC) ผู้เรียกที่ส่งผ่านในการขึ้นต่อกัน ผู้เรียกควบคุมการขึ้นต่อกัน

การควบคุมการพึ่งพาอินสแตนซ์ถูกกลับด้าน - แทนที่จะอยู่ใน "ด้านล่าง" โดยที่โค้ดที่ต้องการคือมันถูกอินสแตนซ์ที่ "top" ซึ่งโค้ดที่ต้องการมันถูกเรียก


1
ภาษาอังกฤษไม่ธรรมดา ล้มเหลว.
Robert Harvey

2
@RobertHarvey - ธรรมดาแค่ไหน?
Oded

4
@RobertHarvey Huh? มันดูธรรมดาสำหรับฉัน ... อะไรที่ไม่ธรรมดา คำว่า "instantiation" หรือ "dependencies"?
จิมมี่ฮอฟฟา

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

สิ่งนี้และโพสต์เป็น @ dsw88 ด้านบนนั้นค่อนข้างธรรมดาสำหรับฉัน ดูสิถ้าฉันไม่เคยได้ยิน IoC ฉันก็จะคิดอย่างสังหรณ์ใจว่า "โอ้ใครจะควบคุมสิ่งที่พลิกจากด้านหนึ่งไปอีกด้านหนึ่ง" ทำได้ดีมาก!
Oliver Williams

2

โดยทั่วไปแล้วการเรียกรหัสระดับที่สูงขึ้น (เช่นตัวควบคุม) รหัสระดับล่าง ฟังก์ชั่นการโทรหลัก (), (), ฟังก์ชั่น () การโทร libraryFunction ()

ที่สามารถคว่ำได้ดังนั้นฟังก์ชั่นห้องสมุดระดับต่ำที่ด้านล่างเรียกฟังก์ชั่นระดับสูงขึ้น

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


1

นี่เป็นภาพรวมอย่างง่าย:

  1. การควบคุมหมายถึงสิ่งที่โปรแกรมทำต่อไป
  2. ในระดับบนสุดโดยทั่วไปมีสองสิ่งที่ควบคุมการควบคุม: แอปพลิเคชันและผู้ใช้

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

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

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


0

ให้เราพยายามทำความเข้าใจผ่านสองตัวอย่าง

ตัวอย่างที่ 1

ในวันก่อนหน้านี้แอพที่ใช้ในการสร้างพรอมต์คำสั่งเพื่อยอมรับอินพุตของผู้ใช้ทีละรายการ วันนี้เฟรมเวิร์กของ UI ทำให้องค์ประกอบ UI ต่าง ๆ ยกตัวอย่างเหตุการณ์ต่าง ๆ ขององค์ประกอบ UI เหล่านั้น (เช่นเมาส์โฮเวอร์คลิก ฯลฯ ) และผู้ใช้ / โปรแกรมหลักมีตะขอ (ตัวอย่างเช่นฟังเหตุการณ์ UI ใน Java) สำหรับฟังเหตุการณ์เหล่านั้น ดังนั้นองค์ประกอบ UI หลัก "การควบคุม" จึงถูกย้ายจากโปรแกรมผู้ใช้ไปยังเฟรมเวิร์ก UI ในวันก่อนหน้ามันอยู่ในโปรแกรมผู้ใช้

ตัวอย่างที่ 2

พิจารณาชั้นCustomerProcessorล่าง:

class CustomerProcessor
{
    SqlCustRepo custRepo = new SqlCustRepo(); 
    private void processCustomers()
    {
            Customers[] custs = custRepo.getAllCusts();
    }
}

หากฉันต้องการprocessCustomer()เป็นอิสระจากการนำไปปฏิบัติใด ๆgetAllCusts()ไม่ใช่แค่ที่จัดทำโดยSqlCustRepoฉันจะต้องกำจัดสาย: SqlCustRepo custRepo = new SqlCustRepo()และแทนที่ด้วยสิ่งทั่วไปมากขึ้นความสามารถในการยอมรับการใช้งานที่หลากหลายเช่นที่processCustomers()จะทำงานให้ การดำเนินการใด ๆ ที่จัดไว้ให้ รหัสข้างต้น (อินสแตนซ์ระดับที่จำเป็นSqlCustRepoโดยตรรกะโปรแกรมหลัก) เป็นวิธีแบบดั้งเดิมและจะไม่ประสบความสำเร็จในเป้าหมายของ decoupling นี้จากการดำเนินงานของprocessCustomers() getAllCusts()ในการผกผันของการควบคุมคอนเทนเนอร์ instantiates ชั้นการดำเนินงานที่จำเป็น (ตามที่ระบุโดยพูดการกำหนดค่า xml), ฉีดมันในตรรกะโปรแกรมหลักซึ่งได้รับการผูกตามตะขอที่ระบุ (พูดโดย@Autowiredคำอธิบายประกอบหรือ getBean()วิธีการในกรอบฤดูใบไม้ผลิ)

ให้ดูว่าสิ่งนี้สามารถทำได้ พิจารณารหัสด้านล่าง

config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="custRepo" class="JsonCustRepo" />
</beans>

CustRepo.java

interface ICustRepo 
{ ... }

JsonCustRepo.java

class JsonCustRepo implements CustRepo
{ ... }

App.java

class App
{
    public static void main(String[] args) 
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
        ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
    }
}

เรายังสามารถมี

class GraphCustRepo implements ICustRepo { ... }   

และ

<bean id="custRepo" class="GraphCustRepo">

และเราไม่จำเป็นต้องเปลี่ยน App.java

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

PS: IoC เป็นแนวคิดทั่วไปและสามารถทำได้หลายวิธี ตัวอย่างข้างต้นประสบความสำเร็จโดยการฉีดพึ่งพา

อ้างอิง: บทความของมาร์ตินฟาวเลอร์

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