【问题标题】:Implementing visitor pattern on aggregate objects在聚合对象上实现访问者模式
【发布时间】:2011-04-05 06:31:47
【问题描述】:

我正在努力将访问者模式应用于一些具有标量成员并同时具有聚合成员(集合)的对象。

这些是我拥有的物品:

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() 界面对我来说有点古怪。我是否应该完全放弃访问者模式并采取不同的方法?

谢谢。

【问题讨论】:

    标签: php aggregate children visitor-pattern


    【解决方案1】:

    我看到Visitor 使用“遍历器”类实现,该类具有要访问的类型的特定知识。在这种情况下,它会“知道”访问Artists 中的WorksOfArt,而不是WorksOfArt 中的Artists。您可以为其他行为定义其他遍历器。

    丹

    这是我挖出的一些伪代码......(实际上是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
    

    【讨论】:

    • 丹,谢谢您的回答。由于我对使用访问者模式有点犹豫,Ian 说服我放弃它。还是谢谢。
    • 嗯。好的。请注意,Visitor 并不特定于递归结构。
    【解决方案2】:

    您实际上并没有说明艺术家和艺术品之间的关系是什么。如果,正如我怀疑的那样,两者都意味着艺术家制作了 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 补充。

    【讨论】:

    • 您说服我放弃了访问者模式。我不知道访问者模式通常用于递归数据。我决定采用您建议的方法,虽然更灵活一些,因为我还需要输出部分片段。但你不可能知道这一点。谢谢。
    猜你喜欢
    • 2015-06-25
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2021-08-05
    • 1970-01-01
    相关资源
    最近更新 更多