วิธีใช้ Dependency Injection ร่วมกับรูปแบบ Factory


10

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

พิจารณาคลาส B ที่ต้องการเนื้อหาของไฟล์ product.xml คลาสนี้จะต้องสร้างอินสแตนซ์ที่เป็นรูปธรรมที่เหมาะสมของตัวแยกวิเคราะห์ Parser เพื่อแยกไฟล์ XML ฉันสามารถมอบอินสแตนซ์ของผู้ใช้งานคอนกรีตที่เหมาะสมให้กับโรงงานเช่นคลาส B "มี" โรงงาน " อย่างไรก็ตามคลาส B จะ "พึ่งพา" ในโรงงานเพื่อสร้างอินสแตนซ์ให้กับผู้ใช้งานที่เป็นรูปธรรม ซึ่งหมายความว่าตัวสร้างหรือวิธีการตั้งค่าในคลาส B จะต้องผ่านโรงงาน

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

คำตอบ:


8

วิธีที่ถูกต้องในการทำสิ่งนี้คือการพึ่งพาอินเทอร์เฟซจากนั้นทำการฉีดอินเทอร์เฟซนั้นไปยังคลาส B

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

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

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

บรรทัดล่าง: อย่าลังเลที่จะฉีดการพึ่งพา นั่นควรเป็นวิธีปกติในการทำสิ่งต่าง ๆ


คอนสตรัคชั่นทำการฉีดสิ่งใหม่ ๆ ออกมานานที่สุดหรือไม่
JeffO

มันแย่มากฉันได้กำหนดให้พูดว่า "แอพของคุณอยู่ไกลที่สุด"
Nick Hodges

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

1
พูดอย่างดี: อย่าลังเลที่จะฉีดการพึ่งพา
Signcodeindie

9

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

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

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

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

กล่าวคือ

IDbConnectionProvider connProvider = DIContainer.Get<IDbConnectionProvider>();
IUserRepository userRepo = new UserRepository(connProvider);
User currentUser = userRepo.GetCurrentUser();

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

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

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


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

ฉันคิดว่าคุณพลาดจุดเพราะ OP ไม่ได้พูดเกี่ยวกับ DI framework หรือ DI container
Doc Brown

@Jimmy Hoffa ในขณะที่คุณทำประเด็นที่น่าสนใจมากฉันทราบเกี่ยวกับภาชนะบรรจุ IoC เช่น Spring และ cconcept ของ Dependency Injection ความกังวลของฉันเกี่ยวกับสถานการณ์ที่คุณไม่ได้ใช้กรอบ IoC ในกรณีนี้คุณต้องเขียนคลาสที่จะยกตัวอย่างการพึ่งพาของคุณให้คุณ หากคลาส A ขึ้นอยู่กับอินเตอร์เฟส B และคลาส C ใช้คลาส A ดังนั้นคลาส C จะขึ้นอยู่กับอินเตอร์เฟส B บางคนต้องการให้คลาส C เป็นคลาส B คลาส C ควรขึ้นอยู่กับ cla
CKing

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

@bot เหมือนที่ฉันพูดไว้ในคำนำส่วนใหญ่คุณสามารถปฏิบัติต่อโรงงานเป็นส่วนย่อยของการทำงานของ DI container มันไม่เป็นความจริงในทุกสถานการณ์ที่ Doc Brown กล่าวถึง แต่ดูที่ตัวอย่างโค้ดของฉันและแทนที่DIContainerด้วยDbConnectionFactoryและแนวคิด ยังคงยืนหยัดว่าคุณจะสามารถดึงการปฏิบัติที่เป็นรูปธรรมจากโรงงาน / ของคุณ / etc และมอบให้กับผู้บริโภคประเภทที่เวลาก่อสร้างของพวกเขา
จิมมี่ฮอฟฟา

5

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

ฉันใช้ DI เพื่อฉีดโรงงานอย่างสม่ำเสมอ


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

4

ไม่มีอะไรผิดปกติในโรงงานฉีด มันเป็นวิธีมาตรฐานถ้าคุณไม่สามารถตัดสินใจได้ในระหว่างการสร้างวัตถุ 'ผู้ปกครอง' ชนิดใดที่คุณต้องพึ่งพา ฉันคิดว่าตัวอย่างจะอธิบายได้ดีที่สุด ฉันจะใช้ c # เพราะฉันไม่รู้จาวา


class Parent
{
    private IParserFactory parserFactory;
    public Parent(IParserFactory factory)
    {
        parserFactory = factory
    }

    public ParsedObject ParseFrom(string filename, FileType fileType)
    {
        var parser = parserFactory.CreateFor(fileType);
        return parser.Parse(filename);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.