我正在开发一个对象模型,它具有许多不同的父/子类。每个子对象都有对其父对象的引用。我可以想到(并且已经尝试过)几种初始化父引用的方法,但是我发现每种方法都有明显的缺点。给定以下所述的方法,哪一种是最好的,哪一种是更好的。
我不会确保下面的代码可以编译,因此如果代码在语法上不正确,请尝试查看我的意图。
请注意,尽管我并不总是显示任何参数,但我的一些子类构造函数确实会接受参数(而不是父参数)。
调用方负责设置父级并添加到同一父级。
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;} } }
缺点:为消费者设置父级过程分为两个步骤。
var child = new Child(parent); parent.Children.Add(child);
缺点:容易出错。调用者可以将子代添加到与用于初始化子代不同的父代中。
var child = new Child(parent1); parent2.Children.Add(child);
父级验证调用者将子级添加到已为其初始化的父级。
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); } }
缺点:呼叫者仍然需要两步来设置父代。
缺点:运行时检查–降低性能,并向每个添加/设置程序添加代码。
当将子级添加/分配给父级时,父级(为其自身)设置子级的父级引用。父级设置器是内部的。
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); } }
缺点:创建子级时没有父级引用。有时初始化/验证需要父代,这意味着必须在孩子的父代设置器中执行一些初始化/验证。代码会变得复杂。如果始终有其父级引用,则实现子级会容易得多。
父级公开工厂添加方法,以便子级始终具有父级引用。子ctor是内部的。父级二传手是私人的。
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; } }
缺点:不能使用初始化语法,例如
new Child(){prop = value}
。而是要做:var c = parent.AddChild(); c.prop = value;
缺点:必须在add-factory方法中复制子构造函数的参数。
缺点:不能为单身儿童使用属性设置器。似乎很la脚,我需要一种方法来设置值,但需要通过属性获取器提供读取访问权限。它不平衡。
子级将自身添加到其构造函数中引用的父级。儿童ctor是公开的。没有来自父级的公共添加访问。
//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;} } }
缺点:调用语法不是很好。通常
add
,在父对象上调用一个方法,而不仅仅是创建这样的对象:var parent = new ParentWithChildren(); new Child(parent); //adds child to parent new Child(parent); new Child(parent);
并设置一个属性,而不是仅仅创建一个像这样的对象:
var parent = new ParentWithChild(); new Child(parent); // sets parent.Child
...
我刚刚了解到SE不允许一些主观问题,显然这是一个主观问题。但是,也许这是一个很好的主观问题。