สำหรับฉันมันเหมาะสมแล้วที่จะให้ชื่อที่เป็นรูปธรรมกับชั้นเรียนแทนที่จะพึ่งพา NamedEntity ทั่วไป ในทางกลับกันมีจำนวนคลาสดังกล่าวที่ไม่มีคุณสมบัติเพิ่มเติม
มีข้อเสียสำหรับวิธีนี้หรือไม่?
วิธีการไม่ได้เลวร้าย แต่มีวิธีแก้ปัญหาที่ดีกว่า กล่าวโดยสรุปอินเตอร์เฟสจะเป็นทางออกที่ดีกว่าสำหรับสิ่งนี้ เหตุผลหลักที่อินเทอร์เฟซและการสืบทอดแตกต่างกันที่นี่เป็นเพราะคุณสามารถสืบทอดจากคลาสเดียวเท่านั้น แต่คุณสามารถใช้อินเทอร์เฟซมากมาย
ตัวอย่างเช่นพิจารณาว่าคุณได้ตั้งชื่อเอนทิตีและเอนทิตีที่ตรวจสอบแล้ว คุณมีหลายหน่วยงาน:
One
ไม่ใช่นิติบุคคลที่ผ่านการตรวจสอบหรือเป็นนิติบุคคลที่มีชื่อ ง่ายมาก:
public class One
{ }
Two
เป็นนิติบุคคลที่มีชื่อ แต่ไม่ใช่นิติบุคคลที่ตรวจสอบแล้ว นั่นคือสิ่งที่คุณมีอยู่ตอนนี้:
public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Two : NamedEntity
{ }
Three
เป็นทั้งรายการที่ระบุชื่อและตรวจสอบแล้ว นี่คือที่ที่คุณพบปัญหา คุณสามารถสร้างAuditedEntity
ชั้นฐาน แต่คุณไม่สามารถทำให้Three
เป็นมรดกทั้งสอง AuditedEntity
และ NamedEntity
:
public class AuditedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
{ }
อย่างไรก็ตามคุณอาจคิดถึงวิธีแก้ปัญหาด้วยการAuditedEntity
รับช่วงNamedEntity
ต่อ นี่เป็นแฮ็คที่ฉลาดเพื่อให้แน่ใจว่าทุก ๆ คลาสจะต้องสืบทอด (โดยตรง) จากคลาสอื่น
public class AuditedEntity : NamedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : AuditedEntity
{ }
ยังคงใช้งานได้ แต่สิ่งที่คุณได้ทำที่นี่คือที่ระบุไว้ว่าทุกกิจการที่ตรวจสอบแล้วเป็นอย่างโดยเนื้อแท้ยังเป็นชื่อนิติบุคคล ซึ่งนำฉันไปเป็นตัวอย่างสุดท้ายของฉัน Four
เป็นนิติบุคคลที่ตรวจสอบแล้ว แต่ไม่ได้เป็นนิติบุคคลที่มีชื่อ แต่คุณไม่สามารถปล่อยให้Four
สืบทอดจากAuditedEntity
ที่คุณจะได้รับNamedEntity
เนื่องจากมรดกระหว่าง AuditedEntity and
NamedEntity`
การใช้การสืบทอดไม่มีวิธีในการทำทั้งสองอย่างThree
และFour
ทำงานนอกเสียจากคุณจะเริ่มคลาสที่ซ้ำกัน (ซึ่งเปิดชุดปัญหาใหม่ทั้งหมด)
การใช้อินเทอร์เฟซสามารถทำได้อย่างง่ายดาย:
public interface INamedEntity
{
int Id { get; set; }
string Name { get; set; }
}
public interface IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class One
{ }
public class Two : INamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Three : INamedEntity, IAuditedEntity
{
public int Id { get; set; }
public string Name { get; set; }
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class Four : IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
ข้อเสียเปรียบเล็กน้อยเพียงอย่างเดียวที่นี่คือคุณยังต้องใช้อินเทอร์เฟซ แต่คุณจะได้รับประโยชน์ทั้งหมดจากการมีชนิดที่นำกลับมาใช้ซ้ำได้โดยไม่ต้องมีข้อเสียใด ๆ ที่เกิดขึ้นเมื่อคุณต้องการรูปแบบที่หลากหลายในประเภททั่วไปสำหรับเอนทิตีที่กำหนด
แต่ความแตกต่างของคุณยังคงเหมือนเดิม:
var one = new One();
var two = new Two();
var three = new Three();
var four = new Four();
public void HandleNamedEntity(INamedEntity namedEntity) {}
public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}
HandleNamedEntity(one); //Error - not a named entity
HandleNamedEntity(two);
HandleNamedEntity(three);
HandleNamedEntity(four); //Error - not a named entity
HandleAuditedEntity(one); //Error - not an audited entity
HandleAuditedEntity(two); //Error - not an audited entity
HandleAuditedEntity(three);
HandleAuditedEntity(four);
ในทางกลับกันมีจำนวนคลาสดังกล่าวที่ไม่มีคุณสมบัติเพิ่มเติม
นี่คือรูปแบบที่เปลี่ยนแปลงในรูปแบบอินเทอร์เฟซของตัวทำเครื่องหมายซึ่งคุณใช้อินเทอร์เฟซที่ว่างเปล่าเพื่อให้สามารถใช้ชนิดของอินเทอร์เฟซเพื่อตรวจสอบว่าคลาสที่กำหนดเป็น "ทำเครื่องหมาย" ด้วยอินเทอร์เฟซนี้
คุณกำลังใช้คลาสที่สืบทอดมาแทนที่จะใช้อินเตอร์เฟส แต่เป้าหมายนั้นเหมือนกันดังนั้นฉันจะเรียกมันว่าเป็น "คลาสที่ทำเครื่องหมาย"
ตามมูลค่าแล้วไม่มีอะไรผิดปกติกับอินเทอร์เฟซ / คลาสของตัวทำเครื่องหมาย พวกเขาเป็นไวยากรณ์และเทคนิคที่ถูกต้องและไม่มีข้อบกพร่องโดยธรรมชาติเพื่อใช้พวกเขาให้เครื่องหมายเป็นความจริงในระดับสากล (ที่รวบรวมเวลา) และไม่ได้มีเงื่อนไข
นี่คือวิธีที่คุณควรแยกความแตกต่างระหว่างข้อยกเว้นต่าง ๆ แม้ว่าข้อยกเว้นเหล่านั้นจะไม่มีคุณสมบัติ / วิธีการเพิ่มเติมใด ๆ เมื่อเปรียบเทียบกับวิธีการพื้นฐาน
ดังนั้นจึงไม่มีอะไรผิดปกติกับการทำเช่นนั้น แต่ฉันจะแนะนำให้ใช้อย่างระมัดระวังเพื่อให้แน่ใจว่าคุณไม่เพียงแค่พยายามปกปิดข้อผิดพลาดทางสถาปัตยกรรมที่มีอยู่ด้วยความหลากหลายที่ออกแบบมาไม่ดี
OrderDateInfo
s จากที่เกี่ยวข้องกับNamedEntity
s