【发布时间】: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