Реализация шаблона посетителя на агрегатных объектах - PullRequest
2 голосов
/ 29 августа 2010

Я борюсь с применением шаблона посетителя для некоторых объектов, которые имеют скалярные элементы и в то же время агрегируют элементы (коллекции).

Это мои объекты:

Artist
 - id
 - name
 - .. more scalar values ..
 - worksOfArt <-- this is a collection as WorkOfArt instances


WorkOfArt
 - id
 - name
 - .. more scalar values ..
 - artists <-- this is a collection of Artist instances

Как вы можете видеть, структура также будет рекурсивной, но это будет беспокоить меня позже.; -)

Мой вопрос: каков наилучший способ реализации шаблона посетителя, который позволяет мне посещать объекты, а также только их посещаемых детей (коллекции).

Я подумал создатьтакой интерфейс:

VisitableAggregateInterface
{
    public function getVisitableChildren(); // this would return only visitable children
}

А затем пусть Artist и WorkOfArt расширяют абстрактный класс следующим образом:

VisitableAggregateAbstract implements VisitableAggregateInterface
{
    public function accept( Visitor $visitor )
    {
        $visitor->visit( $this );
        foreach( $this->getVisitableChildren() as $visitableChild )
        {
           $visitableChild->accept( $visitor );
        }
    }

    /*
        VisitableAggregateInterface::getVisitableChildren()
        will be implemented by Artist and WorkOfArt and will only
        return visitable children (like collections), and not scalar values.
    */
}

В конечном итоге цель состоит в том, чтобы в конечном итоге получить конкретного посетителя, которыйзапишите XML-файл, подобный следующему:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<artgallery>
    <artists>
        <artist>
            <id>1</id>
            <name></name>
            <worksOfArt>
                <workOfArt refid="11"/>
                <workOfArt refid="12"/>
            </worksOfArt>
        <artist>
    <artists>
    <worksOfArt>
        <workOfArt>
            <id>11</id>
            <artists>
                <artist refid="1"/>
            </artists>
            <name></name>
            <info><![CDATA[some info]]></info>
        </workOfArt>
        <workOfArt>
            <id>12</id>
            <artists>
                <artist refid="1"/>
            </artists>
            <name></name>
            <info><![CDATA[some info]]></info>
        </workOfArt>
    </worksOfArt>
</artgallery>

Пожалуйста, совет: я иду в правильном направлении здесь?Потому что интерфейс getVisitableChildren() кажется мне немного странным.Должен ли я, может быть, вообще отказаться от шаблона посетителя и использовать другой подход?

Спасибо.

Ответы [ 2 ]

1 голос
/ 29 августа 2010

Я видел, как Visitor реализован с использованием класса 'traverser', который имеет конкретные знания о типах посещаемых объектов В этом случае было бы «знать» посетить WorksOfArt в Artists, но не Artists в WorksOfArt. Вы можете определить другие траверсеры для другого поведения.

Dan

Вот какой-то псевдокод, который я выкопал ... (на самом деле, но никому не говорите:)):

Видимый:

Public Interface IVisitable
    Sub accept(ByVal visitor As IVisitor)
End Interface

Посетитель:

Public Interface IVisitor
    Sub visit(ByVal visitable As IVisitable)
End Interface

Транспортная тележка:

Public Class PaymentListExportTraverser
    Private payments As PaymentList
    Private visitor As IVisitor

    Public Sub New(ByVal paymentList As PaymentList, ByVal exportVisitor As IVisitor)
        payments = paymentList
        visitor = exportVisitor
    End Sub

    Public Sub traverse()
        For Each p As Payment In payments
            p.accept(visitor)
        Next
    End Sub
End Class
0 голосов
/ 29 августа 2010

Вы на самом деле не утверждаете, какова связь между художником и произведением искусства. Если, как я подозреваю, оба означают, что Artist создал WorkOfArt, то у вас нет рекурсивной структуры данных, поэтому вам не нужен шаблон посетителя.

Я бы просто "грубой силой" это. Как то так (не проверено)

echo "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>
<artgallery>
    <artists>\n";
Foreach (Artists as Artist) {
   echo "        <artist>
            <id>1</id>
            <name></name>
            <worksOfArt>\n";
   ForEach (Artist.worksOfArt as Work) {
      $refid = ????;
      echo "<workOfArt refid=\"$refid"/>\n";
   }
   echo "        </worksOfArt>
        </artist>\n";
}
echo " </artists>
    <worksOfArt>";
Foreach (WorkOfArt as work) {
   ForEach (work.Artists as Artist) {

   }
}

Затем просто поместите остальные операторы echo в вышеприведенное

Кстати - у вас есть опечатка в вопросе. Закрытие и нужно / с добавлено.

...