Tôi đang phát triển một mô hình đối tượng có nhiều lớp cha / con khác nhau. Mỗi đối tượng con có một tham chiếu đến đối tượng cha của nó. Tôi có thể nghĩ ra (và đã thử) một số cách để khởi tạo tham chiếu cha mẹ, nhưng tôi thấy những hạn chế đáng kể đối với mỗi phương pháp. Đưa ra các cách tiếp cận được mô tả dưới đây là tốt nhất ... hoặc thậm chí còn tốt hơn.
Tôi sẽ không đảm bảo mã bên dưới biên dịch, vì vậy hãy thử xem ý định của tôi nếu mã không đúng về mặt cú pháp.
Lưu ý rằng một số hàm tạo của lớp con tôi có các tham số (không phải là cha mẹ) mặc dù tôi không luôn hiển thị bất kỳ.
Người gọi có trách nhiệm thiết lập cha mẹ và thêm vào cùng một cha mẹ.
class Child { public Child(Parent parent) {Parent=parent;} public Parent Parent {get; private set;} } class Parent { // singleton child public Child Child {get; set;} //children private List<Child> _children = new List<Child>(); public List<Child> Children { get {return _children;} } }
Nhược điểm: thiết lập cha mẹ là một quá trình hai bước cho người tiêu dùng.
var child = new Child(parent); parent.Children.Add(child);
Nhược điểm: dễ bị lỗi. Người gọi có thể thêm con vào một cha mẹ khác so với được sử dụng để khởi tạo con.
var child = new Child(parent1); parent2.Children.Add(child);
Phụ huynh xác minh rằng người gọi thêm con vào cha mẹ đã được khởi tạo.
class Child { public Child(Parent parent) {Parent = parent;} public Parent Parent {get; private set;} } class Parent { // singleton child private Child _child; public Child Child { get {return _child;} set { if (value.Parent != this) throw new Exception(); _child=value; } } //children private List<Child> _children = new List<Child>(); public ReadOnlyCollection<Child> Children { get {return _children;} } public void AddChild(Child child) { if (child.Parent != this) throw new Exception(); _children.Add(child); } }
Nhược điểm: Người gọi vẫn có quy trình hai bước để thiết lập cha mẹ.
Nhược điểm: kiểm tra thời gian chạy - làm giảm hiệu suất và thêm mã vào mỗi add / setter.
Cha mẹ đặt tham chiếu cha mẹ của con (cho chính nó) khi con được thêm / gán cho cha mẹ. Cha mẹ setter là nội bộ.
class Child { public Parent Parent {get; internal set;} } class Parent { // singleton child private Child _child; public Child Child { get {return _child;} set { value.Parent = this; _child = value; } } //children private List<Child> _children = new List<Child>(); public ReadOnlyCollection<Child> Children { get {return _children;} } public void AddChild(Child child) { child.Parent = this; _children.Add(child); } }
Nhược điểm: Đứa trẻ được tạo ra mà không có tài liệu tham khảo cha mẹ. Đôi khi khởi tạo / xác nhận yêu cầu cha mẹ có nghĩa là một số khởi tạo / xác nhận phải được thực hiện trong trình thiết lập cha mẹ của con. Các mã có thể nhận được phức tạp. Sẽ dễ dàng hơn nhiều để thực hiện đứa trẻ nếu nó luôn có tài liệu tham khảo cha mẹ của nó.
Cha mẹ trưng bày các phương thức thêm vào nhà máy để một đứa trẻ luôn có một tài liệu tham khảo cho cha mẹ. Ctor trẻ em là nội bộ. Phụ huynh setter là riêng tư.
class Child { internal Child(Parent parent, init-params) {Parent = parent;} public Parent Parent {get; private set;} } class Parent { // singleton child public Child Child {get; private set;} public void CreateChild(init-params) { var child = new Child(this, init-params); Child = value; } //children private List<Child> _children = new List<Child>(); public ReadOnlyCollection<Child> Children { get {return _children;} } public Child AddChild(init-params) { var child = new Child(this, init-params); _children.Add(child); return child; } }
Nhược điểm: Không thể sử dụng cú pháp khởi tạo như
new Child(){prop = value}
. Thay vào đó phải làm:var c = parent.AddChild(); c.prop = value;
Nhược điểm: Phải nhân đôi các tham số của hàm tạo con trong các phương thức add-Factory.
Nhược điểm: Không thể sử dụng trình thiết lập thuộc tính cho một đứa trẻ độc thân. Có vẻ khập khiễng rằng tôi cần một phương pháp để đặt giá trị nhưng cung cấp quyền truy cập đọc thông qua một getter thuộc tính. Nó bị lệch.
Con tự thêm vào cha mẹ được tham chiếu trong hàm tạo của nó. Ctor trẻ em là công khai. Không có quyền truy cập công khai từ cha mẹ.
//singleton class Child{ public Child(ParentWithChild parent) { Parent = parent; Parent.Child = this; } public ParentWithChild Parent {get; private set;} } class ParentWithChild { public Child Child {get; internal set;} } //children class Child { public Child(ParentWithChildren parent) { Parent = parent; Parent._children.Add(this); } public ParentWithChildren Parent {get; private set;} } class ParentWithChildren { internal List<Child> _children = new List<Child>(); public ReadOnlyCollection<Child> Children { get {return _children;} } }
Nhược điểm: cú pháp gọi là không tốt. Thông thường, người ta gọi một
add
phương thức trên cha mẹ thay vì chỉ tạo một đối tượng như thế này:var parent = new ParentWithChildren(); new Child(parent); //adds child to parent new Child(parent); new Child(parent);
Và thiết lập một thuộc tính thay vì chỉ tạo một đối tượng như thế này:
var parent = new ParentWithChild(); new Child(parent); // sets parent.Child
...
Tôi mới biết rằng SE không cho phép một số câu hỏi chủ quan và rõ ràng đây là một câu hỏi chủ quan. Nhưng, có lẽ đó là một câu hỏi chủ quan tốt.