复合设计模式的父组件化

3
我发现使用组合模式时,有一件事可以用不同的方式解决:将父亲元素与另一个组合元素关联。
我的意思是,如果“子”元素应该知道“父”元素,可以通过以下两种方式之一实现:
  • by putting the parent element to the constructor:

    Composite (Composite parent) {
       parent.addChild(this);
       this.parent = parent;
    }
    
     public void addChild(Composite child) {
        children.add(child);
     }
    
  • by using the addChild method which internally assigns a reference of itself to the added child:

    public void addChild(Composite child) {
        children.add(child);
        child.setParent(this);
    }
    

现在,我的问题是要使用哪种方法?哪一种更可靠、更灵活、更少出现错误?有没有人经历过这两种方法,并决定选择其中一种?

1个回答

1

引用自 wikipedia:

组合模式可在客户端需要忽略对象组合和单个对象之间的区别时使用。

由于想法是将一组对象视为单个(相同类型的)对象,通常复合对象会迭代其组(子项),以传播相同的行为。从这个角度来看,在父级中保留子项列表更加合理。

更新:我误解了你的问题。让我再试一次:通常,由于上述原因,复合对象会保留对其子项的引用。父链接可能(或不必要)是多余的。您为什么要保留对父对象的引用?子项之间是否存在共享状态?

更新2:好的,父链接应该存在。在这种情况下,您提到的两种方式在功能上是等效的,这本质上是一个API设计问题。一种TDD思维方式可能会对您有所帮助。例如,由于场景图本质上是一棵树,创建第一个节点的简单场景可以进行测试。以下是我理解的两个版本如何完成此操作:

// First way:
// Shorter but still readable. Parent relationship established at construction, so you can count on that the parent property is always at its final state.
Composite root = new Composite(null);
Composite child = new Composite(root);

// Second way:
// Has an extra statement but more explicit. Also slightly more flexible since the parent relationship can be established _after_ construction. 
Composite root = new Composite();
Composite child = new Composite();
root.addChild(child);

也许重新父节点可能是另一个有趣的测试,如果你有这样的需求。确定你最重要的操作并为它们设计将以最合适的方式塑造API。

是的,我知道...但我忘记在构造函数中将子项添加到子项列表中了...马上修复。 - luke1985
其实我不是那个意思。但现在我明白我误解了你的问题。 - henginy
可能有很多原因要保留到父元素的链接。在我的情况下,我正在开发GUI库和3D场景图。GUI的子元素必须知道父剪辑区域,以便它们不会超出父边界。对于场景图来说,这是为了创建嵌套变换 - 当父对象旋转时,子对象也随之旋转,因此必须知道父当前的变换。 - luke1985
我了解组合设计模式,你实际上是从问题中复制了代码。实际上,你让我思考了一下。我不知道TDD代表什么,但如果你谈论的是测试驱动设计-我们无法在讨论中达成任何观点,因为TDD本质上并不涉及语义学。我想要的是一些场景示例,这些场景可以成为问题的来源,或者另一种方式是它们可以缓解所有痛苦并使代码真正优秀。例如,看看Swing和SWT-SWT在构造函数中使用父级,而Swing使用“addChild”方法。我的问题是“为什么”? - luke1985
我认为你没有理解重点。你问:“哪个更可靠、更灵活、更少出错?”,我的答案是——这取决于具体情况。我在代码中添加了比较的注释,但我们不知道你的确切需求,所以我的建议是使用自己的场景进行测试,这将塑造你的设计。这里的TDD代表测试驱动开发。它有助于以足够简洁的方式设计API,这在语义方面非常相关。上面的代码是你提到的API的“用法”示例,而不是重复的内容。 - henginy
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接