【问题标题】:Object model design; base class awareness of derived classes对象模型设计;派生类的基类意识
【发布时间】:2011-12-12 20:52:34
【问题描述】:

序言:让基类意识到并使用派生类型进行交互是不好的设计吗?我假设不是,那么我应该考虑以下哪种方法?


(语言是 PHP,但我觉得这个问题更关心设计模式这个更广泛的主题)

我一直处于两难境地,试图将一组类建模为节点;我一直在猜测我的设计决策,这导致了永久的挫败感。

给定这组参数:

  • 节点有父引用(单向遍历
  • 从 Node 派生的任何对象类型都可以是从 Node 派生的任何其他对象类型的父(或子)。

所以我有:

abstract class AbstractNode{

    protected $_parent;

    public function __construct(self $parent = null){
        $this->_parent = $parent;
    }

    public function get_parent(){
        return $this->_parent;
    }

}

class NodeOne extends AbstractNode{ }

class NodeTwo extends AbstractNode{ }

// more derivatives

现在我的设计困境出现了;在遍历NodeOne 的过程中,可能需要单独找到实例以及从AbstractNode 派生的任何其他类型实例(请注意,此功能并非NodeOne 实例独有,但这只是一个示例)

这将允许特定类型的遍历,例如,将来自特定类型对象的数据聚合到树上。我想我会专门研究一种方法来达到这个目的:

public function get_node_one_ancestor(){
    if($this->_parent instanceof NodeOne){
        return $this->_parent;
    }
    if(null !== $this->_parent){
        return $this->_parent->get_node_one_ancestor();
    }
    return null;
}

由于任何派生类型都可能需要遍历实例NodeOne,因此将这个方法放在AbstractNode 基类中是有意义的,但是现在我的基类需要了解派生类型。

我觉得这闻起来很糟糕,但我不知道这种方法还应该去哪里。我正在阅读有关可能解决方案的结构设计模式。


想到的一个类比是 DOM,对某些类型进行祖先遍历:

<root>
    <foo id="1">
        <bar id="2"></bar>
        <bar id="3">
            <foo id="4">
                <bar id="5">
                    <foo id="6">
                        <bar id="7"></bar>
                    </foo>
                </bar>
                <bar id="8"></bar>
            </foo>
        </bar>
    </foo>
</root>
  • bar[@id='8']聚合所有foo祖先id值:
    结果4 1

  • bar[@id='7']聚合所有foo祖先id值:
    结果6 4 1

【问题讨论】:

  • 你想用这个实现解决什么问题?嵌套集?
  • 否 @DigitalPrecision -- 它与 RDBMS 树表示无关;它是一个执行树。节点代表过程,任何给定的过程都可以调用任何其他过程。但是有些节点具有环境属性,如果执行具有环境属性的节点(我的示例中的NodeOne),则其中调用的任何节点都需要观察该节点已更改的任何属性,因此我需要回溯以查找NodeOne 的实例,并在调用完成之前聚合/合并属性。它允许级联执行环境。
  • 我明白了。我们在旧代码库中有一个节点类型的实现,但选择不按最初设计的方式移植它,因为复杂性无法保证支持它所花费的时间。

标签: php design-patterns inheritance derived-class tree-traversal


【解决方案1】:

你应该能够概括它:

public function get_ancestor($type){
    if($this->_parent instanceof $type){
        return $this->_parent;
    }
    if(null !== $this->_parent){
        return $this->_parent->get_ancestor($type);
    }
    return null;
}

对我来说,这似乎是可以存在于外部迭代器对象中的东西,但我不能说我在发表这篇文章之前考虑了很多......

【讨论】:

  • 谢谢@Matthew -- 我搞砸了$parent,应该是$this-&gt;_parent -- 正在编辑。
  • 再次感谢@Matthew -- 我已经考虑过了,我正在再次查看其他实现细节,看看这是否合适。
猜你喜欢
  • 2011-01-05
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多