ใช้การฉีดพึ่งพาสำหรับวัตถุข้อมูลหรือไม่


11

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

Class DO{
    DO(){
        DataObject2List = new List<DO2>();
    }

    public string Field1;
    public string Field2;
    public List<DO2> DataObject2List;
}

Class DO2{
    public DateTime Date;
    public double Value;
}

คุณหมายถึงอะไรโดย "วัตถุข้อมูล"? นั่นไม่ใช่คำศัพท์มาตรฐาน คุณกำลังพูดถึงDTOหรือคุณหมายถึงแค่คลาสใด ๆ ที่ไม่มีเมธอด (เช่นส่วนที่น่าเบื่อของโมเดลโดเมน)? มีความแตกต่างอย่างมากระหว่างสองสิ่งนี้
Aaronaught

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

@sooprise นี่เป็นคำถามที่ดี ความคิดที่ดี.
Matthew Rodatus

@sooprise บางทีคำตอบของฉันอาจปิดฐาน คุณจะใส่วิธีการ CRUD ที่ไหน? ในคลาสการเข้าถึงข้อมูลแยกต่างหากที่จะนำ Data Objects และเก็บไว้ในตารางฐานข้อมูล เช่น DataAccess.Create (<DataObject>) หรือไม่
Matthew Rodatus

1
@ แมทท์นี่จะเป็นData Access Object - ถ้านั่นคือสิ่งที่ OP กำลังพูดถึงนั่นก็ไม่ชัดเจนเลย การใช้งานที่ทันสมัยมีแนวโน้มที่จะย้ายออกไปจากรูปแบบนี้อย่างไรก็ตามพึ่งพาที่เก็บและ / หรือหน่วยงาน
Aaronaught

คำตอบ:


7

ฉันอยากจะแนะนำคำศัพท์บางคำที่คุณใช้ที่นี่โดยเฉพาะ "การพึ่งพา" และ "การพึ่งพาการฉีด"

การอ้างอิง:

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

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

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

ฉีดพึ่งพา:

ถ้าDO2ชั้นเรียนของคุณมีฟังก์ชั่นเพิ่มเติมตามDOความต้องการของชั้นเรียนจริงแล้วมันจะเป็นการพึ่งพาอย่างแท้จริง ในกรณีดังกล่าวคลาสที่ขึ้นต่อกันDOควรขึ้นอยู่กับอินเทอร์เฟซ (เช่น ILogger หรือ IDataAccessor) และในทางกลับกันต้องอาศัยรหัสโทรศัพท์เพื่อให้อินเทอร์เฟซนั้น (กล่าวอีกนัยหนึ่งDOคือ

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


7

ฉันจะพยายามอย่างเต็มที่เพื่อลดความสับสนในคำถาม

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

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

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

  • ในที่สุดData Access Objectsจะนำเสนอ wrapper หรือfaçadeให้กับฐานข้อมูลบางประเภท เห็นได้ชัดว่าสิ่งเหล่านี้มีการพึ่งพา - มันขึ้นอยู่กับการเชื่อมต่อฐานข้อมูลและ / หรือส่วนประกอบการคงอยู่ อย่างไรก็ตามการอ้างอิงของพวกเขามักจะถูกจัดการจากภายนอกและมองไม่เห็นผู้โทร ในรูปแบบActive Recordเป็นกรอบการทำงานที่จัดการทุกอย่างผ่านการกำหนดค่า ในรุ่นเก่า (เก่าแก่ตามมาตรฐานในปัจจุบัน) คุณสามารถสร้างแบบจำลอง DAO เหล่านี้ผ่านทางคอนเทนเนอร์เท่านั้น ถ้าฉันเห็นสิ่งเหล่านี้ด้วยการฉีดคอนสตรัคเตอร์ฉันจะเป็นกังวลมาก

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

ในสิ่งเหล่านี้คุณมักจะไม่มีคอนสตรัคเตอร์สำหรับการฉีด แต่คุณต้องทำให้คุณสมบัติเสมือนจริงและใช้ประเภทนามธรรม (เช่นIList<T>แทนList<T>) ส่วนที่เหลือเกิดขึ้นเบื้องหลังและไม่มีใครฉลาด

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

หากต้องการย้ำ:

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

ครีบ.


0

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

จริงๆแล้วคุณจะฉีดอะไรที่นี่บ้าง


ตามคำถามอื่นของเขาที่ฉันตอบฉันคิดว่าคำถามนั้นหมายถึง Data Object ที่มีการดำเนินการ CRUD การพึ่งพาฐานข้อมูลถูกแทรกลงใน Data Object ได้อย่างไร ในวิธีการ? ในตัวสร้างหรือไม่ วิธีอื่นไหม สมมติฐานคือว่าการพึ่งพาไม่ควรถูกซ่อนอยู่ในเนื้อความของวิธีการ - ที่ปิดใช้งานการแยกการอ้างอิงฐานข้อมูลจากวัตถุข้อมูลเพื่อให้วัตถุข้อมูลสามารถทดสอบหน่วย
Matthew Rodatus

@ Matthew Rodatus - ฉันเข้าใจ ใช่ในกรณีนี้คุณมีสองทางเลือก: ฉีดบริการการคงอยู่หรือสร้างคลาสอื่นที่เรียกDOPersisterว่าวิธีการคงอยู่DOและปล่อยให้มันเป็นวัตถุเฉพาะข้อมูลเท่านั้น (ดีกว่าในความคิดของฉัน) ในกรณีหลังDOPersisterจะถูกฉีดด้วยการพึ่งพาฐานข้อมูล
Scott Whitlock

หลังจากอ่านคำถามของเขาอีกครั้งฉันก็ไม่ค่อยแน่ใจ การวิเคราะห์ของฉันอาจผิด เขาพูดด้วยคำถามของเขาว่า DO ของเขาจะไม่มีกระบวนการใด ๆ นั่นหมายความว่าการคงอยู่ไม่เกิดขึ้นใน DO ในกรณีนี้คำตอบของคุณถูกต้อง - ไม่มีการพึ่งพาการฉีด
Matthew Rodatus

0

เนื่องจากนี่คือ Data Object ใน data access layer มันควรขึ้นอยู่กับบริการฐานข้อมูลโดยตรง คุณสามารถระบุ DatabaseService ให้กับตัวสร้าง:

DataObject dataObject = new DataObject(new DatabaseService());
dataObject.Update();

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

DataObject dataObject = new DataObject();
dataObject.Update(new DatabaseService());

แน่นอนคุณไม่ต้องการซ่อนสิ่งก่อสร้างในวิธี CRUD!

public void Update()
{
    // DON'T DO THIS!
    using (DatabaseService dbService = new DatabaseService())
    {
        ...
    }
}

ทางเลือกอื่นคือสร้าง DatabaseService ด้วยวิธีการเรียนแบบ overridable

public void Update()
{
    // GetDatabaseService() is protected virtual, so in unit testing
    // you can subclass the Data Object and return your own
    // MockDatabaseService.
    using (DatabaseService dbService = GetDatabaseService())
    {
        ...
    }
}

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

public void Update()
{
    // The ServiceLocator would not be a real singleton. It would have a setter
    // property so that unit tests can swap it out with a mock implementation
    // for unit tests.
    using (DatabaseService dbService = ServiceLocator.GetDatabaseService())
    {
        ...
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.