2010-08-28 3 views
2

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

Это те объекты, которые у меня есть:

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 
} 

А затем пусть как Исполнитель и 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() чувствует себя немного изворотливым для меня. Должен ли я, возможно, даже вообще сорвать шаблон посетителя и придерживаться другого подхода?

Спасибо.

ответ

0

Вы фактически не указываете, какова связь между художником и произведениями искусства. Если, как я подозреваю, оба означают, что 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) { 

    } 
} 

Тогда просто положить остальные эхо заявления в выше

BTW - у вас есть опечатка в вопросе. Закрытие и необходимость.

+0

Вы убедили меня оставить шаблон посетителя. Я не знал, что шаблон посетителя обычно предназначен для рекурсивных данных. Я решил воспользоваться предложенным вами подходом, хотя и немного более гибким, так как мне также нужно выводить частичные фрагменты. Но ты не мог этого знать. Благодарю. –

1

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

Dan

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

Visitable:

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

Дэн, спасибо за ваш ответ.Так как я уже был на заборе об использовании шаблона посетителя, Иэн убедил меня оставить его. Спасибо, в любом случае. –

+0

Хм. ОК. Имейте в виду, что этот посетитель не относится к рекурсивным структурам. –

Смежные вопросы