ไลบรารี Inject (In) Dependency Inject (มิตร)


230

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

คำถามคือวิธีที่ดีที่สุดในการออกแบบห้องสมุดคือ:

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

ความคิดปัจจุบันของฉันคือการจัดหา "DI registration modules" สองสามข้อสำหรับไลบรารี DI ทั่วไป (เช่นรีจิสทรี StructureMap, โมดูล Ninject) และชุดชั้นเรียนหรือชุดโรงงานที่ไม่ได้เป็น DI และมีการเชื่อมต่อกับโรงงานไม่กี่แห่งเหล่านั้น

คิด?


การอ้างอิงใหม่ไปยังบทความลิงค์ที่ขาด (SOLID): butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
M.Hassan

คำตอบ:


360

นี่เป็นเรื่องง่ายที่จะทำเมื่อคุณเข้าใจว่า DI เกี่ยวกับรูปแบบและหลักการไม่ใช่เทคโนโลยี

ในการออกแบบ API ในวิธี DI Container-Agnostic ให้ปฏิบัติตามหลักการทั่วไปเหล่านี้:

โปรแกรมไปยังส่วนต่อประสานไม่ใช่การใช้งาน

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

ใช้หลักการฮอลลีวูด

ฮอลลีวู้ดหลักการในแง่ DI says: อย่าเรียก DI คอนเทนเนอร์ก็จะโทรหาคุณ

อย่าขอการพึ่งพาโดยตรงจากการเรียกคอนเทนเนอร์จากภายในโค้ดของคุณ ขอมันโดยปริยายโดยใช้สร้างฉีด

ใช้ตัวสร้างการฉีด

เมื่อคุณต้องการการพึ่งพาขอแบบคงที่ผ่านตัวสร้าง:

public class Service : IService
{
    private readonly ISomeDependency dep;

    public Service(ISomeDependency dep)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        this.dep = dep;
    }

    public ISomeDependency Dependency
    {
        get { return this.dep; }
    }
}

สังเกตว่าคลาส Service รับประกันค่าคงที่อย่างไร เมื่อมีการสร้างอินสแตนซ์การอ้างอิงนั้นจะสามารถใช้ได้เนื่องจากการรวมกันของ Guard Clause และreadonlyคำสำคัญ

ใช้ Abstract Factory หากคุณต้องการวัตถุที่มีอายุสั้น

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

ดูสิ่งนี้สำหรับข้อมูลเพิ่มเติม

เขียนเฉพาะช่วงเวลาที่รับผิดชอบครั้งสุดท้ายเท่านั้น

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

รายละเอียดเพิ่มเติมที่นี่:

ลดความซับซ้อนของการใช้ Facade

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

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

public class MyFacade
{
    private IMyDependency dep;

    public MyFacade()
    {
        this.dep = new DefaultDependency();
    }

    public MyFacade WithDependency(IMyDependency dependency)
    {
        this.dep = dependency;
        return this;
    }

    public Foo CreateFoo()
    {
        return new Foo(this.dep);
    }
}

สิ่งนี้จะทำให้ผู้ใช้สามารถสร้าง Foo เริ่มต้นโดยการเขียน

var foo = new MyFacade().CreateFoo();

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

var foo = new MyFacade().WithDependency(new CustomDependency()).CreateFoo();

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


FWIW นานหลังจากที่เขียนคำตอบนี้ผมขยายความแนวคิดนี้และเขียนบล็อกโพสต์ไม่เกี่ยวกับห้องสมุด DI-Friendlyและการโพสต์เกี่ยวกับสหายDI-Friendly กรอบ


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

4
ฉันยังไม่ได้หาโครงการที่ทำทั้งหมดนี้
Mauricio Scheffer

31
นั่นคือวิธีที่เราพัฒนาซอฟท์แวร์ที่ที่ปลอดภัยดังนั้นเราจึงไม่แบ่งปันประสบการณ์ของคุณ ...
Mark Seemann

19
ฉันคิดว่าส่วนหน้าควรเขียนด้วยมือเพราะเป็นตัวแทนของส่วนประกอบต่างๆที่รู้จักกันดี คอนเทนเนอร์ DI ไม่จำเป็นเพราะทุกอย่างสามารถต่อเข้าด้วยมือได้ (คิดว่า DI ของคนจน) โปรดจำไว้ว่า Facade เป็นเพียงคลาสอำนวยความสะดวกเสริมสำหรับผู้ใช้ API ของคุณ ผู้ใช้ขั้นสูงอาจยังต้องการข้าม Facade และต่อสายส่วนประกอบตามความชอบของตนเอง พวกเขาอาจต้องการใช้ DI Contaier ของตัวเองสำหรับสิ่งนี้ดังนั้นฉันคิดว่ามันไม่ดีที่จะบังคับให้ DI Container บังคับให้พวกเขาหากพวกเขาไม่ได้ใช้งาน เป็นไปได้ แต่ไม่แนะนำให้เลือก
Mark Seemann

8
นี่อาจเป็นคำตอบเดียวที่ดีที่สุดที่ฉันเคยเห็นใน SO
Nick Hodges

40

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

public class Service
{
    public Service()
    {
    }

    public void DoSomething()
    {
        SqlConnection connection = new SqlConnection("some connection string");
        WindowsIdentity identity = WindowsIdentity.GetCurrent();
        // Do something with connection and identity variables
    }
}

คุณเขียนแบบนี้:

public class Service
{
    public Service(IDbConnection connection, IIdentity identity)
    {
        this.Connection = connection;
        this.Identity = identity;
    }

    public void DoSomething()
    {
        // Do something with Connection and Identity properties
    }

    protected IDbConnection Connection { get; private set; }
    protected IIdentity Identity { get; private set; }
}

นั่นคือคุณทำสองสิ่งเมื่อคุณเขียนรหัสของคุณ:

  1. พึ่งพาอินเทอร์เฟซแทนคลาสเมื่อใดก็ตามที่คุณคิดว่าการปรับใช้อาจต้องมีการเปลี่ยนแปลง

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

สิ่งเหล่านี้ไม่มีการสันนิษฐานว่ามีอยู่ในไลบรารี DI ใด ๆ และมันก็ไม่ได้ทำให้รหัสยากที่จะเขียนโดยไม่มีใคร

หากคุณกำลังมองหาสิ่งนี้อย่ามองข้ามสิ่งใดไปกว่า. NET Framework:

  • List<T>IList<T>การดำเนินการ หากคุณออกแบบคลาสของคุณให้ใช้IList<T>(หรือIEnumerable<T>) คุณสามารถใช้ประโยชน์จากแนวคิดเช่นการโหลดแบบสันหลังยาวเช่น Linq ถึง SQL, Linq to Entities และ NHibernate ล้วนแล้วแต่อยู่เบื้องหลัง บางคลาสเฟรมเวิร์กยอมรับจริง ๆIList<T>ว่าเป็นอาร์กิวเมนต์ตัวสร้างเช่นBindingList<T>ซึ่งใช้สำหรับคุณลักษณะการโยงข้อมูลหลายอย่าง

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

  • ถ้าคุณเคยทำงานกับองค์ประกอบ WinForms คุณจัดการกับ "การบริการ" เหมือนหรือINameCreationService IExtenderProviderServiceคุณไม่รู้ด้วยซ้ำว่าคลาสคอนกรีตคืออะไร . NET มีคอนเทนเนอร์ IoC ของตัวเองIContainerซึ่งจะถูกใช้สำหรับสิ่งนี้และComponentคลาสมีGetServiceเมธอดซึ่งเป็นตัวระบุเซอร์วิสที่แท้จริง แน่นอนว่าไม่มีสิ่งใดป้องกันคุณจากการใช้อินเทอร์เฟซเหล่านี้ใด ๆ หรือทั้งหมดโดยไม่มีIContainerหรือที่ตั้งเฉพาะ บริการของตัวเองเป็นแบบคู่กับภาชนะเท่านั้น

  • สัญญาใน WCF ถูกสร้างขึ้นทั้งหมดรอบ ๆ อินเทอร์เฟซ คลาสเซอร์วิสคอนกรีตที่แท้จริงมักถูกอ้างอิงโดยชื่อในไฟล์คอนฟิกูเรชันซึ่งโดยพื้นฐานแล้ว DI หลายคนไม่เข้าใจสิ่งนี้ แต่เป็นไปได้ทั้งหมดที่จะแลกเปลี่ยนระบบการกำหนดค่านี้กับคอนเทนเนอร์ IoC อื่น น่าสนใจกว่านี้พฤติกรรมการบริการเป็นตัวอย่างทั้งหมดIServiceBehaviorซึ่งสามารถเพิ่มได้ในภายหลัง อีกครั้งคุณสามารถเชื่อมต่อสิ่งนี้กับคอนเทนเนอร์ IoC ได้อย่างง่ายดายและให้มันเลือกพฤติกรรมที่เกี่ยวข้อง แต่คุณลักษณะนี้สามารถใช้งานได้อย่างสมบูรณ์โดยไม่มี

และอื่น ๆ และอื่น ๆ. คุณจะพบ DI ทั่วทุกแห่งใน. NET มันเป็นเรื่องปกติที่มันทำไปอย่างไร้รอยต่อโดยที่คุณไม่ได้คิดว่ามันเป็น DI

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


2
สิ่งที่เป็นนามธรรมจริงสำหรับคอนเทนเนอร์คือ IServiceProvider ไม่ใช่ IContainer
Mauricio Scheffer

2
@Mauricio: ถูกต้องแล้ว แต่ลองอธิบายให้คนที่ไม่เคยใช้ระบบ LWC เพราะเหตุใดIContainerภาชนะในย่อหน้าเดียวไม่ได้จริง ๆ ;)
Aaronaught

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

@ Jreeter: คุณหมายถึงว่าทำไมพวกเขาถึงไม่private readonlyฟิลด์ มันยอดเยี่ยมถ้าพวกมันถูกใช้โดยคลาสที่ประกาศเท่านั้น แต่ OP ระบุว่านี่คือเฟรมเวิร์ก / โค้ดระดับไลบรารีซึ่งแสดงถึงคลาสย่อย ในกรณีเช่นนี้โดยทั่วไปคุณต้องการการพึ่งพาที่สำคัญที่ต้องเผชิญกับคลาสย่อย ฉันสามารถเขียนprivate readonlyเขตข้อมูลและคุณสมบัติที่มีตัวรับสัญญาณ / ตัวตั้งค่าได้ชัดเจน แต่ ... ทำให้สูญเสียพื้นที่ในตัวอย่างและรหัสอื่น ๆ ที่จะคงไว้ในทางปฏิบัติเพื่อประโยชน์ที่แท้จริง
Aaronaught

ขอบคุณสำหรับการชี้แจง! ฉันคิดว่าเด็กสามารถอ่านฟิลด์แบบอ่านอย่างเดียวได้
jr3

5

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

คำตอบเดิมมีดังนี้:


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

ฉันสิ้นสุดการเขียนของตัวเองง่ายมาก IoC ภาชนะฝังขณะที่ยังให้ความสะดวกในวินด์เซอร์และโมดูล Ninject การรวมไลบรารีเข้ากับคอนเทนเนอร์อื่นเป็นเรื่องของการเดินสายส่วนประกอบอย่างถูกต้องดังนั้นฉันจึงสามารถรวมเข้ากับ Autofac, Unity, StructureMap ได้ทุกอย่าง

ข้อเสียของเรื่องนี้คือฉันหมดความสามารถในnewการรับบริการ ฉันยังต้องพึ่งพาCommonServiceLocatorซึ่งฉันสามารถหลีกเลี่ยงได้ (ฉันอาจ refactor ออกในอนาคต) เพื่อให้คอนเทนเนอร์ที่ฝังตัวง่ายต่อการใช้งาน

รายละเอียดเพิ่มเติมในโพสต์บล็อกนี้

MassTransitดูเหมือนจะพึ่งพาสิ่งที่คล้ายกัน มันมีIObjectBuilderอินเตอร์เฟซที่เป็นจริงของ CommonServiceLocator IServiceLocator กับคู่อื่น ๆ วิธีแล้วก็ดำเนินการนี้สำหรับแต่ละภาชนะเช่นNinjectObjectBuilderและโมดูลปกติ / สิ่งอำนวยความสะดวกเช่นMassTransitModule จากนั้นใช้ IObjectBuilderเพื่อยกตัวอย่างสิ่งที่ต้องการ แน่นอนว่านี่เป็นวิธีการที่ถูกต้อง แต่โดยส่วนตัวแล้วฉันไม่ชอบมันมากนักเพราะมันผ่านไปมาในภาชนะมากเกินไปโดยใช้มันเป็นบริการค้นหา

Monorailใช้ภาชนะของตัวเองเช่นกันซึ่งการดำเนินการดีเก่าIServiceProvider ภาชนะนี้จะใช้ตลอดทั้งกรอบนี้ผ่านอินเตอร์เฟซที่ exposes บริการที่รู้จักกันดี ในการรับคอนเทนเนอร์ที่เป็นรูปธรรมจะมีตัวระบุตำแหน่งผู้ให้บริการในตัว สถานที่วินด์เซอร์ชี้นี้ระบุตำแหน่งผู้ให้บริการวินด์เซอร์ทำให้ผู้ให้บริการที่เลือก

Bottom line: ไม่มีทางออกที่สมบูรณ์แบบ เช่นเดียวกับการตัดสินใจออกแบบปัญหานี้ต้องการความสมดุลระหว่างความยืดหยุ่นการบำรุงรักษาและความสะดวกสบาย


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

@tne การที่คุณพูดถึงฉันว่าเป็น "แสนไร้เดียงสา" เป็นโฆษณาที่ไม่น่ายินดี ฉันเขียนแอปพลิเคชันที่ซับซ้อนโดยไม่ใช้ DI หรือ IoC ใน C #, VB.NET, Java (ภาษาที่คุณคิดว่า "ต้องการ" IoC ตัดสินโดยคำอธิบายของคุณอย่างชัดเจน) ไม่ใช่ข้อ จำกัด ทางภาษา มันเกี่ยวกับข้อ จำกัด ทางแนวคิด ฉันขอเชิญคุณที่จะเรียนรู้เกี่ยวกับการเขียนโปรแกรมการทำงานแทนที่จะหันไปใช้การโจมตีโฆษณาและการโต้แย้งที่ไม่ดี
Mauricio Scheffer

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

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

1
ภาชนะบรรจุ IoC เป็นพจนานุกรมที่ผันแปรได้ทั่วโลกโดยนำค่าพารามิเตอร์มาเป็นเครื่องมือในการให้เหตุผลดังนั้นจึงควรหลีกเลี่ยง IoC (แนวคิด) เช่นเดียวกับใน "อย่าโทรหาเราเราจะโทรหาคุณ" จะใช้เทคนิคทุกครั้งที่คุณผ่านฟังก์ชั่นเป็นค่า แทน DI ให้สร้างแบบจำลองโดเมนของคุณด้วย ADT แล้วเขียนล่าม (cf Free)
Mauricio Scheffer

1

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

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

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

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