代码之家  ›  专栏  ›  技术社区  ›  user35443

访问者模式-接口与抽象类

  •  3
  • user35443  · 技术社区  · 12 年前

    我目前正在尝试为更简单的语言编写一个简单的编译器,但在添加 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 s在一个块中,或者该子块不能由父块终止 For ... If ... EndFor ).

    我的问题是:如果我有一种对所有人来说都很常见的行为 来访者 s、 我应该创建一个抽象的Visitor类吗 virtual 和其他 abstract ?

    会有任何损失吗 来访者 如果我在它的基础上添加默认行为,这有什么意义?

    3 回复  |  直到 10 年前
        1
  •  2
  •   Adi Lester    12 年前

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

    • 继承基类,并为他实现一些或大部分功能(可能会牺牲灵活性)
    • 自己实现整个界面,实现最大的控制和灵活性。
        2
  •  2
  •   GSerjo    12 年前

    对我来说,访问者模式是一个聪明的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);
    

    哪里 Letter 是的基类 A B

        3
  •  1
  •   Doc Brown    12 年前

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

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