2010-03-06 47 views
9

Tôi có một lớp Person và hai lớp kế thừa được gọi là Parent và Child. Phụ huynh có thể có n (các) đứa trẻ và một đứa trẻ có thể có (các) phụ huynh.Làm thế nào để tham chiếu chéo các đối tượng trong các lớp

Cách tốt nhất trong OOD để tạo tham chiếu giữa Phụ huynh và trẻ em là gì.

Tôi có nên tạo Danh sách trong mỗi lớp tham chiếu đến Cha mẹ/Con được kết nối hoặc có cách nào tốt hơn không?

Trả lời

11

Câu hỏi hay.Mối quan hệ nhiều-nhiều-thuần túy thực sự khá hiếm, và nó thường giúp giới thiệu một đối tượng trung gian để mô hình hóa mối quan hệ đó. Điều này sẽ chứng minh vô giá nếu trường hợp sử dụng (khi!) Xuất hiện yêu cầu bắt giữ các thuộc tính liên quan đến mối quan hệ (ví dụ: mối quan hệ con/mẹ là tự nhiên, thay thế, nuôi, vv).

Vì vậy, ngoài các thực thể Person, Parent và Child mà bạn đã xác định, hãy giới thiệu một đối tượng có tên ParentChildRelationship. Một trường hợp của ParentChildRelationship sẽ có một tham chiếu đến chính xác một phụ huynh và một đứa trẻ, và cả hai lớp cha mẹ và trẻ em sẽ tổ chức một bộ sưu tập của các thực thể này. Sau đó, hãy xác định các trường hợp sử dụng mà bạn có để làm việc với các thực thể này và thêm các phương thức trợ giúp thích hợp để duy trì các tham chiếu liên đối tượng. Trong ví dụ dưới đây tôi đã chọn để thêm một phương thức AddChild công khai cho phụ huynh.

alt text

public abstract class Person 
{ 
} 

public class Parent : Person 
{ 
    private HashSet<ParentChildRelationship> _children = 
     new HashSet<ParentChildRelationship>(); 

    public virtual IEnumerable<ParentChildRelationship> Children 
    { 
     get { return this._children; } 
    } 

    public virtual void AddChild(Child child, RelationshipKind relationshipKind) 
    { 
     var relationship = new ParentChildRelationship() 
     { 
      Parent = this, 
      Child = child, 
      RelationshipKind = relationshipKind 
     }; 

     this._children.Add(relationship); 
     child.AddParent(relationship); 
    } 
} 

public class Child : Person 
{ 
    private HashSet<ParentChildRelationship> _parents = 
     new HashSet<ParentChildRelationship>(); 

    public virtual IEnumerable<ParentChildRelationship> Parents 
    { 
     get { return this._parents; } 
    } 

    internal virtual void AddParent(ParentChildRelationship relationship) 
    { 
     this._parents.Add(relationship); 
    } 
} 

public class ParentChildRelationship 
{ 
    public virtual Parent Parent { get; protected internal set; } 

    public virtual Child Child { get; protected internal set; } 

    public virtual RelationshipKind RelationshipKind { get; set; } 
} 

public enum RelationshipKind 
{ 
    Unknown, 
    Natural, 
    Adoptive, 
    Surrogate, 
    StepParent 
} 
+0

Hình ảnh bị thiếu ... Bạn có thể vui lòng đăng hình ảnh lên imgur thay vì thực hiện tham chiếu đến liên kết Dropbox không? – Sometowngeek

1

Nếu bạn có thể giới hạn hướng của hiệp hội để chỉ một chiều, bạn sẽ tiết kiệm cho mình rất nhiều rắc rối (nhưng điều này không phải lúc nào cũng có thể).

một chiều quan hệ:

public class Parent : Person 
{ 
    public IEnumerable<Person> Children { get; } 
} 

Nếu bạn muốn có hiệp hội đi theo một hướng khác là tốt, bạn có thể làm như vậy quá:

Tuy nhiên, bây giờ bạn có một hình tròn tài liệu tham khảo mà bạn cần phải duy trì, và trong khi nó có thể, nó không đặc biệt hiệu quả.

Bạn thường có thể giữ mối quan hệ như một mối quan hệ một chiều bằng cách cho phép trẻ em tăng sự kiện thay vì tham chiếu một cách rõ ràng cha mẹ của chúng.

1

Tôi tưởng tượng rằng một đứa trẻ cũng có thể là cha mẹ xuống dòng (nếu anh ta được may mắn ... hay bất hạnh, tùy thuộc vào quan điểm) vì vậy tôi sẽ đi với một cái gì đó như:

IPerson 
{ 
    string Name {get; set;} 
    string LastName {get; set;} 
    // whatever else - such as sizeOfShoe, dob, etc 
} 

IHaveParents 
{ 
    // might wanna limit this to a fixed size 
    List<IPerson> Parents {get; set;} 
} 

IHaveChildren 
{ 
    List<IPerson> Children {get; set;} 
} 

IHaveSpouse 
{ 
    IPerson Spouse {get; set;} 
} 

public class DudeWithParentsAndChildren : IPerson, IHaveParents, IHaveChildren, IHaveSpouse 
{  
    public void AskMoneyToParents(){throw new Exception("Implement me!");} 
    public void SlapChildren(){} 
    private void CheatOnSpouse(){} 
    // some other stuff that such a dude can do i.e. GoBowling 
} 

Và bạn có thể dễ dàng mở rộng điều này theo bất kỳ cách nào bạn thích khi yêu cầu mới đến (tin tôi đi).

Cập nhật: Vì vậy, trong trường hợp của bạn nếu bạn chỉ muốn một trẻ em có cha mẹ và ngược lại bạn muốn làm điều gì đó như:

public class Child : IPerson, IHaveParents 
{  
    public void AskMoneyToParents(){throw new Exception("Implement me!");} 
} 

public class Parent : IPerson, IHaveChildren, IHaveSpouse 
{  
    public void SlapChildren(){} 
    private void CheatOnSpouse(){} 
    // some other stuff that such a dude can do i.e. GoBowling 
} 

Bằng cách này nếu bạn muốn có một IHaveFriends giao diện bạn có thể (mà về cơ bản buộc người triển khai đưa ra một danh sách các IPersons như một tài sản có tên là Friends). Nếu bạn không cần nó không làm điều đó, nhưng thực tế là bạn có thể dễ dàng làm điều đó chỉ cần thêm một giao diện, mọi thứ khác vẫn giống như bạn có một mô hình khá mở rộng (không nhất thiết là tốt nhất, bạn biết ý tôi là gì).

+0

acctually trong ví dụ của tôi đứa trẻ sẽ không bao giờ trở thành một phụ huynh, nó được ném ra khỏi hệ thống rất lâu trước khi :-) rằng – Zooking

+0

mát mẻ - nhưng đó chỉ là ví dụ, thông điệp mà tôi đang cố gắng để có được là tôi vẫn sẽ tạo ra các lớp học trẻ em và phụ huynh có họ thực hiện tương ứng các IHaveParents và IHaveChildren (khác với IPerson) cho khả năng mở rộng. – JohnIdol

+0

Ok, nhưng trong ví dụ của tôi sẽ có thể chỉ có Giao diện IHaveChildOrParent? Tôi không nói rằng nó sẽ được tốt đẹp chỉ cần tự hỏi nếu nó sẽ có thể chia sẻ hai và nếu có bất kỳ lợi thế. – Zooking

1

Như JohnIdol đã chỉ ra, một đứa trẻ nằm xuống một bên có thể trở thành phụ huynh. Nói cách khác KHÔNG LÀM các lớp con của Phụ Huynh và Con.

class Person 
{ 
    readonly List<Person> _children = new List<Person>(), 
         _parents = new List<Person>(); 

    public IEnumerable<Person> Children 
    { 
     get { return _children.AsReadOnly(); } 
    } 

    public IEnumerable<Person> Parents 
    { 
     get { return _parents.AsReadOnly(); } 
    } 

    public void AddChild(Person child) 
    { 
     _children.Add(child); 
     child._parents.Add(this); 
    } 

    public void AddParent(Person parent) 
    { 
     _parents.Add(parent); 
     parent._children.Add(this); 
    } 

    /* And so on... */ 
} 
+0

Cho dù bạn chọn giới thiệu các lớp cha mẹ và trẻ em thực sự phụ thuộc vào bản chất của hệ thống đang được phát triển. Nếu đó là phả hệ/phần mềm cây gia đình, thì tôi đồng ý bạn sẽ chỉ muốn một lớp Người cụ thể. Nhưng nếu bạn đang phát triển phần mềm để theo dõi các khoản thanh toán bảo dưỡng/trợ cấp trẻ em, thì các lớp cụ thể cho Phụ huynh và Trẻ em có thể sẽ được yêu cầu, vì các thực thể này sẽ có các thuộc tính khá khác nhau và thực tế là đứa trẻ cuối cùng có thể trở thành cha mẹ không liên quan đến hệ thống. –

2
public class Person 
{ 
    Person Parent { get;set; } 
    IList<Person> Children { get;set; } 
} 

Chánh có thể được null khi bạn không biết cha mẹ. Trẻ em có thể không có hoặc trống khi bạn không có con. Vì mỗi đứa trẻ là một người, nó có thể có một phụ huynh hoặc con riêng của mình.

Thiết kế này, tự nó, là tốt cho đến khi bạn cung cấp các kịch bản trường hợp sử dụng chi tiết hơn về cách sử dụng hoặc duy trì nó.

Các vấn đề liên quan