如何实现访问者模式生成XML?

时间:2013-11-06 19:40:32

标签: c# java design-patterns visitor-pattern

我有一个复合类结构,涉及许多类。需要遍历此结构有许多不同的原因(验证,克隆,导出为xml等),因此编写使用访问者模式是有意义的。给出以下类结构

class Owner
{
    public string Name { get; set; }
    public List<Owned> Liked { get; private set; }
    public List<Owned> Disliked { get; private set; }

    public Owner()
    {
        this.Liked = new List<Owned>();
        this.Disliked = new List<Owned>();
    }
}

class Owned
{
    public string Name { get; set; }
}

如果我想像这样生成XML

,应该如何实现这样的访问者模式
<owner>
    <name>Owner 1</name>
    <likedThings>
        <owned>
            <name>Liked thing 1</name>
        </owned>
        <owned>
            <name>Liked thing 2</name>
        </owned>
    </likedThings>
    <dislikedThings>
        <owned>
            <name>Disliked thing 1</name>
        </owned>
        <owned>
            <name>Disliked thing 2</name>
        </owned>
    </dislikedThings>
</owner>

我首先关注的是通常我会使用VisitOwner和VisitOwned,这样可以很好地进行验证,但在XML中我需要将Owned对象包装在各自的likesThings或dislikedThings XML节点中。

我担心的第二件事是,我希望每个现有的访问者实现都有一个编译时错误,该实现尚未对组合的任何新部分实施操作(例如,新属性“List&lt; Owned&gt; SmellyThings”)

1 个答案:

答案 0 :(得分:4)

Visitor Pattern允许您为问题的双重调度方构建结构,帮助您处理由模型的继承结构引起的复杂性。但是,模式的经典形式无法解决由于模型的组合结构而导致的复杂性,特别是当同一个类在不同的容量中多次使用时。

在您的情况下,解决方案必须解决这两个复杂问题 - 一方面,您拥有OwnerOwned;另一方面,您有LikedDisliked以及您计划添加的任何其他内容。

处理组合方面的任务传统上是给访问者的实现,而不是接口。但是,编译器无法帮助您找到无法处理新关系的违规者。但是,您可以将访问者模式与Template Method Pattern结合使用,以创建一个处理这两个问题的混合解决方案。

以下是您可以执行的操作的框架:

// This is a run-of-the-mill visitor
interface IVisitor {
    void VisitOwner(Owner owner);
    void VisitOwned(Owned owned);
}
// This is a base visitor class; it is abstract
abstract class DefaultVisitor : IVisitor {
    public void VisitOwner(Owner owner) {
        BeginOwner(owner);
        BeginLiked();
        foreach (var owned in owner.Liked) {
            owned.Accept(this);
        }
        EndLiked();
        BeginDisliked();
        foreach (var owned in owner.Disliked) {
            owned.Accept(this);
        }
        EndDisliked();
        EndOwner(owner);
    }
    public void VisitOwned(Owned owned) {
        BeginOwned(owned);
        EndOwned(owned);
    }
    public abstract void BeginOwner(Owner owner);
    public abstract void EndOwner(Owner owner);
    public abstract void BeginOwned(Owned owned);
    public abstract void EndOwned(Owned owned);
    public abstract void BeginLiked();
    public abstract void EndLiked();
    public abstract void BeginDisliked();
    public abstract void EndDisliked();
}

构造代码的优点是编译器现在可以检查DefaultVisitor的实现是否存在所有抽象方法;缺点是这些实现必须提供八个实现而不是两个。