Преамбула. Плохой ли дизайн для базового класса, если он знает о производных типах и взаимодействует с ними? Я предполагаю, что нет, так какой подход я должен рассмотреть для следующего?
(Язык — это 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
NodeOne
из моего примера) выполняется, любые узлы, вызываемые в нем, должны отслеживать любые свойства, которые изменил этот узел, поэтому мне нужно вернуться назад. чтобы найти экземплярыNodeOne
и объединить/объединить свойства до завершения вызова. Это позволяет использовать каскадную среду выполнения. - person Dan Lugg   schedule 13.12.2011