ใช้อินเทอร์เฟซสำหรับประเภทข้อมูลเป็นแบบป้องกันหรือไม่


9

สมมติว่าฉันมีเอนทิตีต่าง ๆ ในแบบจำลองของฉัน (โดยใช้ EF), พูดว่าผู้ใช้ผลิตภัณฑ์ใบแจ้งหนี้และใบสั่ง

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

บทสรุปจะมีเพียง ID และคำอธิบายเท่านั้นดังนั้นฉันจึงสร้างอินเทอร์เฟซอย่างง่ายสำหรับสิ่งนี้:

 public interface ISummarizableEntity {     
       public string ID { get; }    
       public string Description { get; } 
 }

จากนั้นสำหรับเอนทิตีที่มีปัญหาฉันสร้างคลาสบางส่วนที่ใช้อินเทอร์เฟซนี้:

public partial class User : ISummarizableEntity
{
    public string ID
    {
        get{ return UserID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
    }
}

public partial class Product: ISummarizableEntity
{
    public string ID
    {
        get{ return ProductID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
    }
}

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

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

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


มีเหตุผลอะไรที่คุณชอบที่จะมีบางอย่างที่เหมือนEntitySummaryกันโดยที่UserและProductแต่ละวิธีมีวิธีเช่นpublic EntitySummary GetSummary()?
Ben Aaronson

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

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

คำตอบ:


17

การเชื่อมต่อไม่ได้อธิบายพฤติกรรม ค่อนข้างตรงข้ามบางครั้ง

อินเทอร์เฟซอธิบายสัญญาเช่น "ถ้าฉันจะเสนอวัตถุนี้กับวิธีใด ๆ ที่ยอมรับ ISummarizableEntity วัตถุนี้จะต้องเป็นเอนทิตีที่สามารถสรุปตัวเอง" - ในกรณีของคุณที่ถูกกำหนดให้สามารถส่งคืน ID สตริงและคำอธิบายสตริง

นั่นเป็นการใช้อินเทอร์เฟซที่สมบูรณ์แบบ ไม่มีรูปแบบการต่อต้านที่นี่


2
"การเชื่อมต่อไม่ได้อธิบายพฤติกรรม" "สรุปตัวเอง" ไม่ใช่พฤติกรรมอย่างไร
Doval

2
@ThomasStringer การสืบทอดจากมุมมองผู้พิถีพิถันของ OO แสดงถึงบรรพบุรุษที่พบบ่อย (เช่นรูปสี่เหลี่ยมจัตุรัสและวงกลมมีทั้งรูปร่าง ) ในตัวอย่างของ OP ผู้ใช้และผลิตภัณฑ์จะไม่แชร์บรรพบุรุษที่เหมาะสม การสืบทอดในกรณีนี้จะเป็นรูปแบบการต่อต้านที่ชัดเจน
Kent A.

2
@Doval: ฉันเดาชื่อของอินเทอร์เฟซที่อาจอธิบายพฤติกรรมที่คาดหวัง แต่มันไม่จำเป็นต้อง; อินเทอร์เฟซอาจมีชื่อเท่า ๆ กัน IHasIdAndDescription และคำตอบจะเหมือนกัน ส่วนต่อประสานนั้นไม่ได้อธิบายพฤติกรรม แต่อธิบายถึงความคาดหวัง
สาธารณรัฐประชาธิปไตยประชาชนลาว

2
@pdr หากคุณส่ง 20V ผ่านแจ็คหูฟังสิ่งเลวร้ายจะเกิดขึ้น รูปร่างไม่เพียงพอ มีความคาดหวังที่แท้จริงและสำคัญมากสำหรับชนิดของสัญญาณที่จะผ่านเข้ามาในปลั๊ก นี่เป็นสาเหตุที่ทำให้การแกล้งอินเทอร์เฟซไม่มีข้อมูลจำเพาะพฤติกรรมที่แนบมานั้นผิด คุณสามารถทำอะไรกับสิ่งListที่ไม่ทำงานเหมือนในรายการ?
Doval

3
ปลั๊กไฟฟ้าที่มีอินเทอร์เฟซที่เหมาะสมอาจพอดีกับเต้าเสียบ แต่นั่นไม่ได้หมายความว่ามันจะนำไฟฟ้า (พฤติกรรมที่ต้องการ)
JeffO

5

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


3
การเชื่อมต่อไม่มีส่วนเกี่ยวข้องกับการสืบทอด
DougM

1
@DougM บางทีฉันอาจจะพูดไม่ได้ดี แต่ฉันค่อนข้างมั่นใจว่าเราเห็นด้วย
Kent A.

1

อินเตอร์เฟสที่มีคุณสมบัติเท่านั้นที่ควรหลีกเลี่ยงตั้งแต่:

  • มันทำให้เสียความตั้งใจ: คุณเพียงต้องการที่เก็บข้อมูล
  • มันส่งเสริมมรดก: น่าจะเป็นที่ใครบางคนจะผสมความกังวลในอนาคต
  • มันป้องกันการเป็นอันดับ

ที่นี่คุณกำลังผสมสองข้อกังวล:

  • สรุปเป็นข้อมูล
  • สรุปเป็นสัญญา

ข้อมูลสรุปประกอบด้วยสองสาย: id และคำอธิบาย นี่คือข้อมูลธรรมดา:

public class Summary {
    private readonly string id;
    private readonly string description;
    public Summary(string id, string description) {
        this.id = id;
        this.description = description;
    }
    public string Id { get { return id; } }
    public string Description { get { return description; } }
}

ตอนนี้คุณได้กำหนดว่าบทสรุปใดที่คุณต้องการกำหนดสัญญา:

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

โปรดทราบว่าการใช้ปัญญาใน getters เป็นรูปแบบต่อต้านและควรหลีกเลี่ยง: ควรอยู่ในฟังก์ชันแทน นี่คือลักษณะการใช้งาน:

public partial class User : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = UserID.ToString();
        var description = String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age);
        return new Summary(id,description);
    }
}

public partial class Product : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = ProductID.ToString();
        var description = String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department);
        return new Summary(id,description);
    }
}

"อินเทอร์เฟซที่มีคุณสมบัติเท่านั้นที่ควรหลีกเลี่ยง" ฉันไม่เห็นด้วย ให้เหตุผลว่าทำไมคุณถึงคิดเช่นนั้น
ร่าเริง

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