2010-08-28 51 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

你实际上并没有说明艺术家和艺术品之间的关系是什么。正如我怀疑的那样,如果两者都是指艺术家制作了作品,那么您就没有递归数据结构,因此您不需要访问者模式。

我会简单地“蛮力”它。事情是这样的(未经测试)

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语句的其余部分进入上述

顺便说一句 - 你有问题的错字。关闭和需要添加。

+0

你说服我留下访客模式。我并不知道访问者模式通常用于递归数据。我决定采取你建议的方法,虽然更灵活一点,因为我也需要输出部分片段。但你不可能知道这一点。谢谢。 – 2010-08-29 22:54:05

1

我见过Visitor使用具有特定的访问类型知识的“遍历器”类实现。在这种情况下,它将'知道'访问WorksOfArt,Artists而不是ArtistsWorksOfArt。您可以为其他行为定义其他移动器。

下面是一些伪代码,我挖出来......(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

丹,谢谢你的回答。因为我已经习惯了使用访客模式,Ian说服我把它留下。不管怎么说,还是要谢谢你。 – 2010-08-29 22:50:48

+0

嗯。好。请注意,虽然访问者并不特定于递归结构。 – 2010-08-30 14:22:28