Проектиране на обектен модел; осведоменост за базов клас за производни класове

Преамбюл: Лош дизайн ли е базовият клас да бъде наясно и да осъществява взаимодействия с помощта на производни типове? Предполагам, че не, така че какъв подход трябва да обмисля за следното?


(Езикът е 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


person Dan Lugg    schedule 12.12.2011    source източник
comment
Какъв проблем се опитвате да разрешите с тази реализация? Вложен набор?   -  person Mike Purcell    schedule 13.12.2011
comment
Не @DigitalPrecision -- Няма нищо общо с дървовидното представяне на RDBMS; това е дърво за изпълнение. Възлите представляват процедури и всяка дадена процедура може да извика всяка друга процедура. Някои възли обаче имат свойства на средата и ако се изпълни възел със свойства на средата (NodeOne от моя пример), всички възли, извикани в него, трябва да наблюдават каквито и свойства да е променил този възел, следователно трябва да премина обратно за намиране на екземпляри на NodeOne и агрегиране/сливане на свойства, преди извикването да може да бъде завършено. Позволява среда за каскадно изпълнение.   -  person Dan Lugg    schedule 13.12.2011
comment
Виждам. Имахме тип изпълнение на възел тук в по-стара кодова база, но избрахме да не го пренесем, както е първоначално проектирано, защото сложността не гарантираше времето, необходимо за поддръжката му.   -  person Mike Purcell    schedule 13.12.2011


Отговори (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;
}

За мен изглежда, че това е нещо, което може да живее във външен обект на итератор, но не мога да кажа, че съм мислил много преди да направя този пост...

person Matthew    schedule 12.12.2011
comment
Благодаря, @Matthew -- сбърках $parent, трябваше $this->_parent -- редактиране. - person Dan Lugg; 13.12.2011
comment
Благодаря отново @Matthew -- обмислих това, преглеждам отново други подробности за внедряването, за да видя дали това ще пасне. - person Dan Lugg; 13.12.2011