การเขียนโปรแกรมไปยังอินเทอร์เฟซ Data Oriented


9

มีบางส่วนของ codebase ของเราเขียนในรูปแบบต่อไปนี้:

// IScheduledTask.cs
public interface IScheduledTask
{
    string TaskName { get; set; }
    int TaskPriority { get; set; }
    List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein
}

// ScheduledTaskImpl.cs
public class ScheduledTaskImpl : IScheduledTask
{
    public string TaskName { get; set; }
    public int TaskPriority { get; set; }
    public List<IScheduledTask> Subtasks { get; set; }
    // ... several more properties in this vein, 
    // perhaps a constructor or two for convenience.
}

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


1
เหตุผลหนึ่งที่ฉันทำเพื่อความเข้ากันได้กับ COM แต่นั่นไม่ได้เป็นเหตุผลของคุณที่นี่
Mike

@ ไมค์น่าสนใจฉันไม่เคยใช้ COM และไม่ได้ใช้ที่นี่ ฉันจะถามผู้เขียนของส่วนนี้ของรหัสว่าเขาวางแผนที่จะใช้ COM หรืออะไร
walpen

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

6
IMHO มันเป็นมากกว่าความหลงใหลและผิดของรหัสอินเตอร์เฟซที่ไม่ได้ดำเนินการ คีย์บอกเล่าเรื่องราวคือการดำเนินการ แต่เพียงผู้เดียว จุดของอินเทอร์เฟซคือ polymorphism แต่คลาสคุณสมบัติอย่างเดียวคือ polymorphic ในแง่ง่ายโดยมีค่าแตกต่างกัน แม้จะมีพฤติกรรม - วิธีการ - ก็ไม่มีอะไรชี้ให้เห็นว่ามีการใช้งานเพียงครั้งเดียว เรื่องไร้สาระนี้อยู่เหนือฐานรหัสของเราและที่ดีที่สุดมันขัดขวางการบำรุงรักษา ฉันเสียเวลามากเกินไปที่จะถามว่าทำไมอะไรและที่ไหน ทำไมพวกเขาถึงทำสิ่งที่ฉันไม่เห็นการออกแบบและการใช้งานอื่น ๆ อยู่ที่ไหน?
Radarbob

2
ส่วนใหญ่ของความคิดเห็นก่อนหน้าไปที่การใช้งานครั้งเดียว "กลิ่นรหัส" ของนามธรรมก่อนวัยอันควร; อย่างไรก็ตามยังมีโมเดลโดเมนโลหิตจาง "code ดมกลิ่น" ที่นี่โปรดดู: martinfowler.com/bliki/AnemicDomainModel.html
Erik Eidt

คำตอบ:


5

นี่คือสองเซ็นต์ของฉัน:

  • เราไม่แน่ใจว่า DTO จะไม่เคยมีพฤติกรรมอย่างน้อยนิด ดังนั้นสำหรับฉันมีวัตถุที่อาจมีหรือไม่มีพฤติกรรมในอนาคต
  • สาเหตุหนึ่งที่เป็นไปได้ของการมีชั้นเรียน แต่เพียงผู้เดียวการดำเนินงานจำนวนมากดังนั้นการขาดของการออกแบบเช่นความล้มเหลวที่จะเห็นว่าScheduledTask, ScheduledJob, ScheduledEvent, ScheduledInspectionฯลฯ ควรจะมีเพียงหนึ่งแยกSchedulableอินเตอร์เฟซที่ทำให้ schedulable implementor ใด ๆ
  • การสร้างส่วนต่อประสานแรกนั้นเป็นวิธีปฏิบัติที่ดีมากมันช่วยให้คุณเข้าใจถึงสิ่งที่คุณต้องการ อินเทอร์เฟซจำนวนมากเริ่มต้นโดยไม่มีการใช้งานเลย จากนั้นมีคนเขียนหนึ่งการใช้งานและพวกเขามีสิ่งนั้น สถานะของการใช้งานเพียงอย่างเดียวนั้นชั่วคราวถ้าคุณหลีกเลี่ยงสิ่งที่ฉันพูดถึงในจุดที่สอง คุณจะรู้ได้อย่างไรว่าอินเทอร์เฟซบางตัวไม่เคยมีการใช้งานที่สองในสาม
  • ชื่อที่เราเลือกสำหรับอินเทอร์เฟซที่คิดดีมีแนวโน้มที่จะไม่เปลี่ยนแปลงในอนาคตดังนั้นการพึ่งพาอินเทอร์เฟซนั้นจะไม่ได้รับผลกระทบ ในอีกทางหนึ่งชั้นคอนกรีตมีแนวโน้มที่จะเปลี่ยนชื่อเมื่อสิ่งที่สำคัญในทางที่จะดำเนินการเปลี่ยนแปลงตัวอย่างเช่นชั้นคอนกรีตชื่อTaxSheetสามารถเปลี่ยนเป็นSessionAwareTaxSheetเพราะยกเครื่องที่สำคัญได้ทำ แต่อินเตอร์เฟซITaxSheetจะไม่ถูกเปลี่ยนชื่อได้อย่างง่ายดาย

ด้านล่างบรรทัด:

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

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

1

ปัญหาเฉพาะที่ฉันเคยเห็นกับ DTOs ที่ใช้อินเตอร์เฟสคือมันอนุญาตสิ่งนี้:

public interface ISomeDTO { string SomeProperty { get; set; }}

public class SomeDTO : ISomeDTO
{
    public string SomeProperty { get; set; }
    string ISomeDTO.SomeProperty { get { /* different behavior */ } set { SomeProperty = value; } }
}

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

SomeDTO a = GetSomeDTO();
ISomeDTO ia = a;
Assert.IsTrue(a.SomeProperty == ia.SomeProperty); // assert fails!

นี่เป็นเรื่องยากที่จะรักษาและสร้างความสับสนให้พยายามที่จะแก้ให้หายยุ่งหรือ refactor IMO การเพิ่มพฤติกรรมให้กับ DTO นั้นเป็นการละเมิดหลักการความรับผิดชอบเดียว วัตถุประสงค์ของ DTO คือการแสดงข้อมูลในรูปแบบที่สามารถคงอยู่และมีประชากรโดยเฟรมเวิร์กการคงอยู่

DTO ไม่ใช่โมเดลของโดเมน เราไม่ควรกังวลหาก DTO เป็นโลหิตจาง หากต้องการอ้างอิงการอภิปรายของ Martin Fowler เกี่ยวกับโมเดลโดเมนโลหิตจาง :

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

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