การพึ่งพาการฉีดกับรูปแบบโรงงาน


498

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

เมื่อมีคนบอกฉันว่ามันเป็นวิธีที่คุณใช้มันสร้างความแตกต่าง!

ฉันเคยใช้StructureMap a DI container เพื่อแก้ปัญหาหลังจากนั้นฉันออกแบบมันขึ้นมาใหม่เพื่อทำงานกับโรงงานที่เรียบง่ายและลบการอ้างอิงไปที่ StructureMap

ใครสามารถบอกฉันได้ว่าอะไรคือความแตกต่างระหว่างพวกเขากับที่จะใช้อะไรแนวปฏิบัติที่ดีที่สุดที่นี่คืออะไร


21
วิธีการทั้งสองนี้ไม่สามารถสอดคล้องกันได้หรือไม่: ใช้ Dependency Injection เพื่อฉีดคลาสของโรงงาน
Richard Ev

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

2
@gideon จะไม่บังคับให้คุณรวบรวมแอปของคุณหรืออย่างน้อยโมดูลที่มีคลาสจากโรงงาน
กรด lysergic

1
@liortal yep ใช่แล้ว การศึกษาเกี่ยวกับ DI มานานแล้วตั้งแต่ความคิดเห็นนั้นและตอนนี้ฉันเข้าใจว่า DI ใช้วิธีการจากโรงงานหนึ่งก้าวไปข้างหน้า
gideon

1
ลองดูคำตอบที่ยอดเยี่ยมนี้: stackoverflow.com/questions/4985455/… - เขาพูดได้ดีมากและให้ตัวอย่างโค้ด
Luis Perez

คำตอบ:


293

เมื่อใช้โรงงานรหัสของคุณยังคงรับผิดชอบในการสร้างวัตถุ โดย DI คุณว่าจ้างบุคคลภายนอกให้รับผิดชอบคลาสอื่นหรือกรอบงานซึ่งแยกจากโค้ดของคุณ


172
รูปแบบ DI ไม่ต้องการกรอบงานใด ๆ คุณสามารถทำ DI โดยการเขียนโรงงานที่ทำ DI ด้วยตนเอง เฟรมเวิร์ก DI ทำให้ง่ายขึ้น
Esko Luontola

28
@Perpetualcoder - ขอบคุณ @Esko - อย่าติดกับกรอบของคำซึ่งหมายถึงห้องสมุดบุคคลที่สามขั้นสูง
willcodejavaforfood

4
+1 @ รหัสยืนยันขอบคุณ! ดังนั้นคุณต้องเปลี่ยนไฟล์ config / xml แทน ฉันเห็น. ลิงค์ wiki en.wikipedia.org/wiki/…กำหนดรูปแบบของโรงงานเป็นManually-Injected Dependency
gideon

5
ฉันไม่ได้รับประโยชน์จากการเปลี่ยน XML 1 บรรทัดเทียบกับการเปลี่ยนรหัส 1 บรรทัด คุณสามารถทำอย่างละเอียด?
Rafael Eyng

1
ทำซ้ำคำตอบ OP แทนที่ "DI" ด้วย "factory" ยังคงสมเหตุสมผล
Edson Medina

219

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


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

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

1
คำตอบที่ดี หลายคนสับสนกับคำถามนั้น: "ฉันควรเลือก pattens อะไร?" ในความเป็นจริงรูปแบบการออกแบบเป็นเพียงวิธีการแก้ปัญหาในสถานการณ์ที่เหมาะสม หากคุณไม่ทราบว่าควรใช้รูปแบบการออกแบบใดหรือ "ฉันควรใช้รูปแบบใด ดังนั้นคุณไม่จำเป็นต้องใช้ในเวลานี้
Benyi

2
ฉันคิดว่ามันแม่นยำมากกว่าที่จะบอกว่า Factory Pattern เป็นเครื่องมือในการใช้ IoC (ไม่ใช่ DI) โปรดทราบว่าDI เป็นรูปแบบของ IoC
Hooman Bahreini เมื่อ

185

ฉีดพึ่งพา

แทนที่จะเป็นอินสแตนซ์ของชิ้นส่วนรถยนต์ถามหาชิ้นส่วนที่จำเป็นในการทำงาน

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

โรงงาน

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

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

ผลลัพธ์

อย่างที่คุณเห็นโรงงานและ DI เติมเต็มซึ่งกันและกัน

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

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

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

ตัวอย่าง # 1 - นี่คือสิ่งที่เลวร้ายที่สุดเพราะมันซ่อนการพึ่งพาทั้งหมด ถ้าคุณดูวิธีการเป็นกล่องดำคุณคงไม่รู้ว่ามันต้องใช้รถ

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

ตัวอย่างที่ 3 - นี้เหมาะเพราะวิธีการถามว่าสิ่งที่มันต้องการ ไม่มากหรือน้อยเกินไป ฉันไม่ต้องเขียน MockCarFactory เพียงเพื่อสร้าง MockCars ฉันสามารถส่ง mock ตรงเข้าไปได้มันเป็นระบบโดยตรงและส่วนต่อประสานไม่ได้โกหก

Google Tech Talk โดย Misko Hevery น่าอัศจรรย์และเป็นพื้นฐานของสิ่งที่ฉันได้รับจากตัวอย่าง http://www.youtube.com/watch?v=XcT4yYu_TTs


1
รูปแบบโรงงานถูกฉีดเป็น DI
Mangesh Pimpalkar

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

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

3
นี่ไม่ใช่รูปแบบ DI นี่เป็นเพียงการนำ IoC ไปใช้ DI ใช้ ServiceLocator เพื่อกำหนดการพึ่งพาที่ถูกต้องและแทรกลงในตัวสร้างในระหว่างการสร้างวัตถุรหัสของคุณจะแยกการสร้างวัตถุออกจากขอบเขตคลาสของคุณเท่านั้น
Diego Mendes

3
@DiegoMendes สิ่งที่คุณอธิบายคือกรอบงานที่ทำให้ DI เป็นแบบอัตโนมัติ ServiceLocator ตามที่คุณเรียกว่า DI สำหรับคุณ สิ่งที่ฉันแสดงคือรูปแบบของตัวเองซึ่งไม่ต้องการกรอบงานแฟนซีใด ๆ ดูstackoverflow.com/a/140655/1160036หรือดู en.wikipedia.org/wiki/… : "[รายชื่อเฟรมเวิร์ก] สนับสนุนการพึ่งพาการฉีด แต่ไม่จำเป็นต้องทำการฉีดพึ่งพา" นอกจากนี้ "การฉีดคือการผ่านการพึ่งพาวัตถุที่ขึ้นต่อกัน" คุณกำลังสับสนกับแนวคิดที่เรียบง่าย
Despertar

50

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

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

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

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

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


3
นี่เป็นคำตอบที่ดีที่สุด ... คำตอบอื่น ๆ ไม่ได้พูดถึง IoC หรือจำไม่ได้ว่า DI เป็นรูปแบบของ IoC
Hooman Bahreini

ขอบคุณเมื่อฉันศึกษา IOC ครั้งแรกฉันเกือบจะกรีดร้องว่านี่เป็นรูปแบบของโรงงานอีกรูปแบบกลับกลายเป็นว่าพวกเขามีความคล้ายคลึงกันจริงๆ
Harvey Lin

40

มีปัญหาที่แก้ได้ง่ายด้วยการฉีดแบบพึ่งพาซึ่งไม่สามารถแก้ไขได้ง่ายด้วยชุดของโรงงาน

ความแตกต่างบางประการระหว่างตรงกันข้ามการควบคุมและการพึ่งพาการฉีด (IOC / DI) และตรงกันข้ามผู้ให้บริการหรือโรงงาน (โรงงาน) คือ:

IOC / DI เป็นระบบนิเวศที่สมบูรณ์ของวัตถุโดเมนและบริการในและของตัวเอง มันตั้งค่าทุกอย่างสำหรับคุณในแบบที่คุณระบุ วัตถุและบริการโดเมนของคุณสร้างโดยคอนเทนเนอร์และไม่ได้สร้างเอง: ดังนั้นจึงไม่มีการอ้างอิงใด ๆบนคอนเทนเนอร์หรือในโรงงานใด ๆ IOC / DI ช่วยให้สามารถกำหนดค่าได้ในระดับสูงมากด้วยการกำหนดค่าทั้งหมดในที่เดียว (การสร้างคอนเทนเนอร์) ที่ชั้นบนสุดของแอปพลิเคชันของคุณ (GUI, ส่วนหน้าของเว็บ)

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


26

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


22

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

จาก: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

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

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

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


14

ทฤษฎี

มีสองจุดสำคัญที่ควรพิจารณา:

  1. ใครเป็นคนสร้างวัตถุ

    • [โรงงาน]: คุณต้องสร้างวัตถุวิธีควรสร้าง คุณมีคลาส Factory แยกต่างหากซึ่งมีตรรกะการสร้าง
    • [การพึ่งพาการฉีด]: ในกรณีที่ปฏิบัติจะทำโดยกรอบภายนอก (ตัวอย่างเช่นใน Java ที่จะเป็นฤดูใบไม้ผลิ / ejb / guice) การฉีดเกิดขึ้น "อย่างน่าอัศจรรย์" โดยไม่มีการสร้างวัตถุใหม่อย่างชัดเจน
  2. วัตถุประเภทใดที่จัดการ:

    • [โรงงาน]: มักจะรับผิดชอบในการสร้างวัตถุที่มีสถานะ
    • [การพึ่งพาการฉีด] มีแนวโน้มที่จะสร้างวัตถุไร้สัญชาติ

ตัวอย่างการใช้งานจริงทั้งในโรงงานและการฉีดในโครงการเดียว

  1. สิ่งที่เราต้องการสร้าง

โมดูลแอปพลิเคชันสำหรับสร้างคำสั่งซื้อที่มีหลายรายการเรียกว่า orderline

  1. สถาปัตยกรรม

สมมติว่าเราต้องการสร้างสถาปัตยกรรมเลเยอร์ต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

วัตถุโดเมนอาจเป็นวัตถุที่เก็บอยู่ในฐานข้อมูล Repository (DAO) ช่วยในการดึงข้อมูลวัตถุจากฐานข้อมูล บริการให้ API กับโมดูลอื่น ๆ แจ้งเตือนสำหรับการทำงานในorderโมดูล

  1. Domain Layer และการใช้งานของโรงงาน

เอนทิตีที่จะอยู่ในฐานข้อมูลคือ Order และ OrderLine คำสั่งซื้อสามารถมีได้หลายรายการ ความสัมพันธ์ระหว่างคำสั่งซื้อและคำสั่งซื้อ

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

แต่วิธีการสร้างคำสั่งโดยไม่มีความรู้เกี่ยวกับ OrderLines

โรงงาน

คนที่ต้องการสร้างคำสั่งซื้อใหม่ใช้ OrderFactory (ซึ่งจะซ่อนรายละเอียดเกี่ยวกับความจริงที่ว่าเราสร้างคำสั่งซื้อ)

ป้อนคำอธิบายรูปภาพที่นี่

นั่นคือวิธีที่มันจะดูภายใน IDE คลาสภายนอกdomainแพ็กเกจจะใช้OrderFactoryแทนตัวสร้างภายในOrder

  1. การพึ่งพาการฉีดการพึ่งพาการใช้กันทั่วไปกับเลเยอร์ไร้สัญชาติเช่นพื้นที่เก็บข้อมูลและบริการ

OrderRepository และ OrderService ได้รับการจัดการโดยกรอบการฉีดพึ่งพา พื้นที่เก็บข้อมูลมีหน้าที่ในการจัดการการดำเนินงาน CRUD บนฐานข้อมูล บริการอัดฉีดพื้นที่เก็บข้อมูลและใช้เพื่อบันทึก / ค้นหาคลาสโดเมนที่ถูกต้อง

ป้อนคำอธิบายรูปภาพที่นี่


คุณช่วยอธิบายให้ฟังหน่อยได้ไหม? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsฉันไม่เข้าใจว่าทำไม
Maksim Dmitriev

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

12

ฉันรู้ว่าคำถามนี้เก่า แต่ฉันต้องการเพิ่มห้าเซ็นต์ของฉัน

ฉันคิดว่าการฉีดพึ่งพา (DI) นั้นมีหลายวิธีเช่น Factory Pattern (FP) ที่กำหนดค่าได้และในแง่นี้สิ่งใดก็ตามที่คุณสามารถทำกับ DI ได้คุณจะสามารถทำกับโรงงานดังกล่าวได้

ที่จริงแล้วถ้าคุณใช้สปริงตัวอย่างเช่นคุณมีตัวเลือกของการเก็บข้อมูลอัตโนมัติ (DI) หรือทำสิ่งนี้:

MyBean mb = ctx.getBean("myBean");

จากนั้นใช้อินสแตนซ์ 'mb' เพื่อทำอะไรก็ได้ นั่นเป็นการโทรไปยังโรงงานที่จะส่งคืนอินสแตนซ์ของคุณหรือไม่?

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

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

ทีนี้, สำหรับสิ่งหนึ่ง, เพื่อให้คุณรู้ว่าอะไรคือการนำไปใช้งานสำหรับ bean ใด ๆ ที่คุณ autowire ด้วย DI, คุณต้องไปที่การกำหนดค่าเอง

แต่ ... สัญญาเกี่ยวกับสิ่งนั้นที่คุณจะไม่ต้องรู้ในการใช้งานวัตถุที่คุณกำลังใช้อยู่? pfft! อย่างจริงจัง? เมื่อคุณใช้วิธีการเช่นนี้ ... คุณไม่เหมือนกันที่เขียนการใช้งานหรือไม่? และแม้ว่าคุณจะไม่ทำคุณแทบจะตลอดเวลาดูว่าการใช้งานทำในสิ่งที่ควรทำอย่างไร ??

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

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

ดังนั้นถ้าฉันมีคลาสที่ทำงานแตกต่างกันในสองขอบเขตในแอปพลิเคชันเดียวกัน (สมมติว่า บริษัท สองแห่งของโฮลดิ้ง) ฉันต้องกำหนดกรอบการทำงานเพื่อสร้างสองถั่วที่แตกต่างกันและปรับรหัสของฉันเพื่อใช้งาน ไม่เหมือนกับฉันจะเขียนแบบนี้:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

เช่นเดียวกับนี้:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

และนี่:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

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

มันคงจะดีถ้าทำอะไรแบบนี้:

MyBean mb = (MyBean)MyFactory.get("mb"); 

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

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

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

อย่างไรก็ตามส่วนความคิดเห็นหากเปิดให้คุณฆ่าฉัน


3
นักพัฒนาหลายคนคิดว่า Dependency Injection Framework นั้นถูกสร้างขึ้นเพื่อนำสิ่งใหม่ ๆ มาใช้ ตามที่คุณอธิบายไว้โรงงานแบบดั้งเดิม (ส่วนใหญ่มักเป็นโรงงานนามธรรม) สามารถมีบทบาทเดียวกันกับการผกผันของการพึ่งพา ผกผันกับการฉีด? สำหรับฉัน "ประโยชน์" เพียงอย่างเดียวของกรอบงานการพึ่งพาการพึ่งพาคือเราไม่ได้เปลี่ยน / คอมไพล์โค้ดใหม่ (เนื่องจากบ่อยครั้งที่สามารถกำหนดค่าได้ด้วย XML เช่น Spring) เมื่อเพิ่ม / เปลี่ยนแปลงการพึ่งพา ทำไมต้องหลีกเลี่ยงการคอมไพล์ซ้ำ เพื่อหลีกเลี่ยงข้อผิดพลาดของมนุษย์ที่อาจเกิดขึ้นในขณะที่เปลี่ยนการพึ่งพา / โรงงาน แต่ด้วย IDEs ที่ยอดเยี่ยมของเราการปรับโครงสร้างจะเล่นได้ดี :)
Mik378

6

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


4

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

ด้วยโรงงานบางคนต้องเรียกคนเหล่านั้นเพื่อรับวัตถุที่สร้างขึ้นไปยังสถานที่ที่พวกเขาต้องการ

ความแตกต่างส่วนใหญ่อยู่ในหนึ่งบรรทัดนี้ที่เรียกโรงงานและดึงวัตถุที่สร้างเสร็จแล้ว

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


3

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

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

หน่วยงานปกครองของอาณาจักรเล็ก ๆ น้อย ๆ คือ "โรงงาน"

รัฐบาลใหญ่คือ "หัวฉีดพึ่งพา"


1
ดังนั้นเมื่อไรที่ผู้เขียนโค้ดคนหนึ่งจะทำรัฐบาลเล็ก ๆ ก่อนหน้านี้ให้กลายเป็นเรื่องใหญ่? วัดเท่าไหร่?
ZERO Prisoner

3

คุณสามารถดูลิงค์นี้เพื่อเปรียบเทียบวิธีสอง (และอื่น ๆ ) ในตัวอย่างจริง

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

สิ่งนี้ยังใช้ได้กับ manual DI (เช่นเมื่อไม่มีกรอบภายนอกที่ให้การอ้างอิงกับวัตถุของคุณ แต่คุณส่งมันในแต่ละ Constructor)


3

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

เมื่อมีคนบอกฉันว่ามันเป็นวิธีที่คุณใช้มันสร้างความแตกต่าง!

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

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

ในกรณีclientนี้ไม่สามารถรับจาก DI (หรืออย่างน้อยก็ต้องมีวิธีแก้ปัญหาที่น่าเกลียด) ดังนั้นตามกฎทั่วไปในการตัดสินใจ: หากสามารถพึ่งพาได้โดยไม่ต้องมีพารามิเตอร์ที่คำนวณจากรันไทม์ใด ๆ ดังนั้นจึงควรเลือก DI มิฉะนั้นให้ใช้ Factory


2

ฉันเชื่อว่า DI เป็นวิธีการกำหนดค่าหรือการสร้างถั่วในทันที DI สามารถทำได้หลายวิธีเช่น constructor, setter-getter เป็นต้น

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

ตรวจสอบลิงค์นี้: ฉีดพึ่งพา


2

Binoj,

ฉันไม่คิดว่าคุณต้องเลือกอย่างใดอย่างหนึ่ง

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

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


2

ฉันเชื่อว่าสิ่งสำคัญ 3 ประการที่ควบคุมการใช้วัตถุและการใช้งาน:
1. การสร้างอินสแตนซ์ (ของคลาสพร้อมกับการเริ่มต้นถ้ามี)
2. การฉีด (ของอินสแตนซ์ที่สร้างขึ้น) ที่ต้องการ
3. การจัดการวงจรชีวิต (ของอินสแตนซ์ที่สร้างขึ้น)

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

ในทางกลับกันการใช้ DI (ของรูปแบบ IoC) ทั้ง 3 รายการจะถูกแยกออกนอกโค้ด (ไปยังคอนเทนเนอร์ DI) และถั่วที่ได้รับการจัดการไม่ต้องการความซับซ้อนใด ๆ เลย Loose Couplingเป้าหมายทางสถาปัตยกรรมที่สำคัญมากสามารถทำให้เงียบได้อย่างสบาย อีกหนึ่งเป้าหมายเชิงสถาปัตยกรรมที่สำคัญคือการแยกความกังวลสามารถทำได้ดีกว่าโรงงาน

ในขณะที่โรงงานอาจเหมาะสำหรับการใช้งานขนาดเล็กโรงงานขนาดใหญ่ควรเลือก DI มากกว่าโรงงาน


1

ความคิดของฉัน:

Dependecy Injection: ส่งผู้ทำงานร่วมกันเป็นพารามิเตอร์ไปยังตัวสร้าง Dependency Injection Framework: โรงงานทั่วไปและกำหนดค่าได้เพื่อสร้างวัตถุที่จะส่งผ่านเป็นพารามิเตอร์ให้กับตัวสร้าง


1
ใช่แล้ว เกือบทั้งหมดกล่าวถึงการฉีดพึ่งพา (DI) ใน Q & A นี้ใช้ผิดคำในทางตรงกันข้ามกับคำนิยามนี้ Dependency Injection Container (DIC) เป็นกรอบทั่วไปที่ทำหน้าที่เป็นโรงงานทั่วไปและกำหนดค่าได้เพื่อสร้างวัตถุ
CXJ

1

กรอบงานการฉีดเป็นการนำรูปแบบโรงงานมาใช้

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

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

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


1

รูปแบบการออกแบบจากโรงงาน

รูปแบบการออกแบบจากโรงงานมีเอกลักษณ์เฉพาะด้วย

  • อินเทอร์เฟซ
  • ชั้นเรียนการดำเนินงาน
  • โรงงาน

คุณสามารถสังเกตบางสิ่งเมื่อคุณถามตัวเองดังนี้

  • โรงงานจะสร้างวัตถุสำหรับคลาสการนำไปใช้งาน - เวลารันหรือเวลารวบรวม
  • ถ้าคุณต้องการเปลี่ยนการใช้งาน ณ รันไทม์? - เป็นไปไม่ได้

เหล่านี้ได้รับการจัดการโดยการฉีดพึ่งพา

ฉีดพึ่งพา

คุณสามารถมีวิธีการต่าง ๆ ที่คุณสามารถฉีดพึ่งพา สำหรับความเรียบง่ายมาพร้อมกับอินเตอร์เฟสการฉีด

ใน DI คอนเทนเนอร์สร้างอินสแตนซ์ที่จำเป็นและ "แทรก" ลงในวัตถุ

จึงกำจัดการสร้างอินสแตนซ์แบบคงที่

ตัวอย่าง:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

จากมูลค่าใบหน้าพวกเขาดูเหมือนกัน

ในแง่ง่ายมากรูปแบบโรงงานรูปแบบการสร้างช่วยสร้างวัตถุให้เรา - "กำหนดอินเทอร์เฟซสำหรับการสร้างวัตถุ" หากเรามีการเรียงลำดับค่าคีย์ของกลุ่มออบเจ็กต์ (เช่นพจนานุกรม) ผ่านคีย์ไปยังโรงงาน (ฉันหมายถึงรูปแบบโรงงานอย่างง่าย) คุณสามารถแก้ไขประเภทได้ งานเสร็จแล้ว! Framework Injection อ้างอิง (เช่นแผนผังโครงสร้าง, Ninject, Unity ... ฯลฯ ) ในทางกลับกันดูเหมือนว่าจะทำสิ่งเดียวกัน

แต่ ... "อย่าบูรณาการล้อ"

จากมุมมองของสถาปัตยกรรมมันเป็นชั้นที่มีผลผูกพันและ "อย่าบูรณาการล้อ"

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

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

หากสิ่งที่คุณมีคือค้อนทุกอย่างดูเหมือนเล็บ

ขึ้นอยู่กับความต้องการของคุณและประเภทของแอปพลิเคชันที่คุณสร้างคุณต้องเลือก หากมีเพียงไม่กี่โครงการ (อาจเป็นหนึ่งหรือสอง .. ) และเกี่ยวข้องกับการอ้างอิงน้อยคุณสามารถเลือกวิธีที่ง่ายกว่า มันเหมือนกับการใช้การเข้าถึงข้อมูล ADO .Net ผ่านการใช้ Entity Framework สำหรับการโทรฐานข้อมูลแบบ 1 หรือ 2 อย่างง่าย ๆ โดยที่การแนะนำ EF นั้นเป็นเรื่องที่เกินความจำเป็นในสถานการณ์นั้น

แต่สำหรับโครงการที่มีขนาดใหญ่ขึ้นหรือถ้าโครงการของคุณใหญ่ขึ้นฉันขอแนะนำอย่างยิ่งให้มีเลเยอร์ DI ที่มีเฟรมเวิร์กและให้มีพื้นที่สำหรับเปลี่ยนเฟรมเวิร์ก DI ที่คุณใช้ (ใช้ Facade ในแอพหลัก (Web App, Web Api, Desktop) ..etc.)


1

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

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

ดู Constructor คุณจะต้องผ่านIAddressModelFactoryมันเท่านั้นดังนั้นพารามิเตอร์ที่น้อยลง *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

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

*) รหัสมาจาก nopCommerce


1

กล่าวง่ายๆคือวิธีการพึ่งพาการฉีดกับวิธี Factory หมายถึงกลไกการกดและแรงดึงตามลำดับ

กลไกการดึง : คลาสทางอ้อมมีการพึ่งพาวิธีการของโรงงานซึ่งในทางกลับกันก็ต้องพึ่งพาคลาสคอนกรีต

กลไกการผลัก : องค์ประกอบของรูทสามารถกำหนดค่าได้ด้วยส่วนประกอบที่ขึ้นต่อกันทั้งหมดในที่เดียวและทำให้การบำรุงรักษาสูงและคลัปหลวม

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


0

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

เรากำลังใช้ Spring Framework ใน Java สำหรับ DI คลาสซิงเกิล ( Parent) ต้องยกตัวอย่างวัตถุใหม่ของคลาสอื่น ( Child) และมีผู้ทำงานร่วมกันที่ซับซ้อน:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

ในตัวอย่างParentนี้จะต้องรับDepXอินสแตนซ์เท่านั้นเพื่อส่งต่อไปยังตัวChildสร้าง มีปัญหากับสิ่งนี้:

  1. Parentมีความรู้Childมากกว่าที่ควร
  2. Parent มีผู้ทำงานร่วมกันมากกว่าที่ควร
  3. การเพิ่มการพึ่งพาเพื่อChildเกี่ยวข้องกับการเปลี่ยนแปลงParent

นี่คือเมื่อฉันรู้ว่าFactoryจะพอดีที่นี่อย่างสมบูรณ์แบบ:

  1. มันซ่อนทั้งหมดยกเว้นพารามิเตอร์ที่แท้จริงของChildชั้นเรียนตามที่เห็นParent
  2. มันสรุปความรู้ในการสร้างChildซึ่งสามารถรวมศูนย์ในการกำหนดค่า DI

นี่คือParentคลาสที่ง่ายและChildFactoryคลาส:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

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


-1

ฉันใช้ทั้งสองอย่างเพื่อสร้างกลยุทธ์ Inversion Of Control ที่มีความสามารถในการอ่านได้มากขึ้นสำหรับนักพัฒนาที่ต้องการรักษามันไว้หลังจากฉัน

ฉันใช้ Factory เพื่อสร้างวัตถุ Layer ที่แตกต่างกัน (Business, Data Access)

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

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

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

ดังนั้นรหัสของฉันโรงงานพึ่งพาโครงสร้างการฉีดคือ:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

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

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


-4

การใช้การฉีดพึ่งพาจะดีกว่ามากในความคิดของฉันถ้าคุณ: 1. การปรับใช้รหัสของคุณในพาร์ทิชันขนาดเล็กเพราะมันจัดการได้ดีใน decoupling ของรหัสขนาดใหญ่หนึ่ง 2. ความสามารถในการทดสอบเป็นหนึ่งในกรณีที่ DI นั้นใช้งานได้เพราะคุณสามารถเยาะเย้ยวัตถุที่ไม่แยกอิสระได้อย่างง่ายดาย ด้วยการใช้อินเทอร์เฟซคุณสามารถจำลองและทดสอบแต่ละวัตถุได้อย่างง่ายดาย 3. คุณสามารถแก้ไขแต่ละส่วนของโปรแกรมได้พร้อมกันโดยไม่จำเป็นต้องเขียนโค้ดส่วนอื่น ๆ ของมันตั้งแต่มันแยกออกจากกันอย่างหลวม ๆ

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