访客模式 - 界面与抽象类

时间:2014-03-23 08:09:12

标签: c# interface abstract-class visitor

我正在尝试为更简单的语言编写一个简单的编译器,但是我在添加Visitor模式时遇到了问题。 我有一个ILanguageVisitor界面,如下所示:

interface ILanguageVisitor {
        void Visit(GlobalStructure cs);
        void Visit(GotoStructure cs);
        void Visit(IfStructure cs);
        void Visit(ElseIfStructure cs);
        void Visit(ElseStructure cs);
        ...
}

必须实现所有这些方法以创建特定体系结构的具体访问者。但除此之外,还有一些方法和领域应该适用于所有可能的访问者。

这就是块的功能,它包含两个或更多Visit个调用,如:

Visit(If) 
    ...
Visit(Else) 
    ... 
Visit(EndIf) 

Visit(For) 
    ... 
Visit(EndFor)

这是因为块启动和终止的规则(就像一个块中不能有两个else,或者父块不能终止子块{{1} })。

我的问题是:如果我的行为对于所有For ... If ... EndFor都应该是通用的,那么我应该创建一个抽象的Visitor类,它会使这些特定的方法Visitor和其他{{1} }?

如果我向其基础添加默认行为,是否会丢失virtual点?

3 个答案:

答案 0 :(得分:2)

在这种情况下,我认为最好的解决方案是同时拥有一个实现此接口的接口和基类,并允许用户覆盖某些方法。这样,用户可以决定他是否愿意:

  • 继承基类并且已经为他实现了一些或大部分功能(可能具有灵活性)
  • 自己实现整个界面,实现最大程度的控制和灵活性。

答案 1 :(得分:2)

至于我,访客模式是一个聪明的If-Else结构,看看这个解决方案

public static class Visitor
{
    public static IFuncVisitor<TBase, TResult> For<TBase, TResult>()
        where TBase : class
    {
        return new FuncVisitor<TBase, TResult>();
    }

    public static IActionVisitor<TBase> For<TBase>()
        where TBase : class
    {
        return new ActionVisitor<TBase>();
    }

    private sealed class ActionVisitor<TBase> : IActionVisitor<TBase>
        where TBase : class
    {
        private readonly Dictionary<Type, Action<TBase>> _repository =
            new Dictionary<Type, Action<TBase>>();

        public void Register<T>(Action<T> action)
            where T : TBase
        {
            _repository[typeof(T)] = x => action((T)x);
        }


        public void Visit<T>(T value)
            where T : TBase
        {
            Action<TBase> action = _repository[value.GetType()];
            action(value);
        }
    }

    private sealed class FuncVisitor<TBase, TResult> : IFuncVisitor<TBase, TResult>
        where TBase : class
    {
        private readonly Dictionary<Type, Func<TBase, TResult>> _repository =
            new Dictionary<Type, Func<TBase, TResult>>();

        public void Register<T>(Func<T, TResult> action)
            where T : TBase
        {
            _repository[typeof(T)] = x => action((T)x);
        }

        public TResult Visit<T>(T value)
            where T : TBase
        {
            Func<TBase, TResult> action = _repository[value.GetType()];
            return action(value);
        }
    }
}

public interface IFuncVisitor<in TBase, TResult>
    where TBase : class
{
    void Register<T>(Func<T, TResult> action)
        where T : TBase;

    TResult Visit<T>(T value)
        where T : TBase;
}

public interface IActionVisitor<in TBase>
    where TBase : class
{
    void Register<T>(Action<T> action)
        where T : TBase;

    void Visit<T>(T value)
        where T : TBase;
}

用法示例:

IActionVisitor<Letter> visitor = Visitor.For<Letter>();
visitor.Register<A>(x => Console.WriteLine(x.GetType().Name));
visitor.Register<B>(x => Console.WriteLine(x.GetType().Name));

Letter a = new A();
Letter b = new B();
visitor.Visit(a);
visitor.Visit(b);

其中LetterAB

的基类

答案 2 :(得分:1)

设计模式是设计问题的解决方案,而不是实施规则。因此,如果您选择使用接口,抽象类或两者(如@AdiLester建议)实现访问者模式完全由您决定

如果我没记错的话,原来的GOF书中使用了很多C ++的例子,其中甚至没有语言元素接口。