我正在努力将访问者模式应用于某些具有标量成员且同时聚合成员(集合)的对象。
这些是我拥有的对象:
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()
界面对我来说有点古怪。我是否应该完全放弃访客模式并采取不同的方法?
感谢。
答案 0 :(得分:1)
我见过Visitor
使用'traverser'类实现,该类具有要访问的类型的特定知识。在这种情况下,您将“知道”访问WorksOfArt
中的Artists
,而Artists
中的WorksOfArt
。您可以为其他行为定义其他遍历器。
丹
这是我挖出的一些伪代码......(实际上是vb,但不要告诉任何人:)):
可访问:
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
答案 1 :(得分:0)
您实际上并未说明艺术家与艺术品之间的关系。如果,正如我怀疑的那样,两者都意味着艺术家制作了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语句放入上面的
中 顺便说一句 - 你的问题有一个错字。关闭和需要/ s添加。