65.9K
CodeProject 正在变化。 阅读更多。
Home

动态访问者模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (17投票s)

2013年3月17日

CPOL

2分钟阅读

viewsIcon

55181

downloadIcon

245

访问者设计模式 - 动态实现。

引言   

访问者“代表对对象结构元素执行的操作。访问者允许您定义新的操作,而无需更改其操作的元素的类” (GoF).

我相信您了解访问者设计模式,因此这里介绍动态实现。动态访问者将模式与业务逻辑分开。访问者模式基于双重分派,因此我们应该实现运行时分派。例如,我们可以通过dynamicType来实现这一点。

所有示例中都使用了以下类层次结构

 

基于“Dynamic”的访问者

dynamic类型在运行时解析。通过将具体类型指定为dynamic类型,我们可以分派到具体的动作。

代码由几个类组成

  • Visitor - 访问者工厂
  • IActionVisitor<in TBase> - 访问者的接口

IActionVisitor<in TBase> - 允许您在具体类型上注册Action<T>

public interface IActionVisitor<in TBase>
        where TBase : class
{
    /// <summary>
    /// Register action on <see cref="T"/>.
    /// </summary>
    /// <typeparam name="T">Concrete type.</typeparam>
    /// <param name="action">Action.</param>
    void Register<T>(Action<T> action)
        where T : TBase;

    /// <summary>
    /// Visit concrete type.
    /// </summary>
    /// <param name="value">Type to visit.</param>
    void Visit<T>(T value)
        where T : TBase;
}  

Visitor - 用于IActionVisitor<in TBase>访问者的工厂。

public static class Visitor
{
    /// <summary>
    /// Create <see cref="IActionVisitor{TBase}"/>.
    /// </summary>
    /// <typeparam name="TBase">Base type.</typeparam>
    /// <returns>New instance of <see cref="IActionVisitor{TBase}"/>.</returns>
    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, dynamic> _repository =
            new Dictionary<Type, dynamic>();

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

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

神奇之处在于这里 

private readonly Dictionary<Type, dynamic> _repository = new Dictionary<Type, dynamic>(); 

以及这里

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

DLR(动态语言运行时)解析类型并执行具体的动作。

示例 

    private static void DynamicActionVisitor()
    {
        Stopwatch stopwatch = Stopwatch.StartNew();

        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);

        stopwatch.Stop();
        Console.WriteLine("Execution time: {0} ms", stopwatch.Elapsed.TotalMilliseconds);
    }  

以下是运行结果

 

第一次使用运行时魔术的调用代价太高,因此基于dynamic的访问者仅在多次调用时才有效。

基于“Type”的访问者

通过将具体类型指定为Action<T>,我们可以分派到具体的动作。

代码由几个类组成

  • Visitor - 访问者工厂
  • IActionVisitor<in TBase> - 访问者的接口

IActionVisitor<in TBase> - 允许您在具体类型上注册Action<T>

public interface IActionVisitor<in TBase>
        where TBase : class
{
    /// <summary>
    /// Register action on <see cref="T"/>.
    /// </summary>
    /// <typeparam name="T">Concrete type.</typeparam>
    /// <param name="action">Action.</param>
    void Register<T>(Action<T> action)
        where T : TBase;

    /// <summary>
    /// Visit concrete type.
    /// </summary>
    /// <param name="value">Type to visit.</param>
    void Visit<T>(T value)
        where T : TBase;
}  

Visitor - 用于IActionVisitor<in TBase>访问者的工厂。

public static class Visitor
{
    /// <summary>
    /// Create <see cref="IActionVisitor{TBase}"/>.
    /// </summary>
    /// <typeparam name="TBase">Base type.</typeparam>
    /// <returns>New instance of <see cref="IActionVisitor{TBase}"/>.</returns>
    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);
        }
    }
}   

神奇之处在于这里,我们创建新的Action<TBase>并且不会丢失具体类型

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

以及这里。我们使用value.GetType()在运行时解析对象类型

         public void Visit<T>(T value)
            where T : TBase

        {
            Action<TBase> action = _repository[value.GetType()];
            action(value);
        } 

示例 

    private static void DynamicActionVisitor()
    {
        Stopwatch stopwatch = Stopwatch.StartNew();

        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);

        stopwatch.Stop();
        Console.WriteLine("Execution time: {0} ms", stopwatch.Elapsed.TotalMilliseconds);
    }  

以下是运行结果

 

基于“Type”的访问者 -完整版本 

IActionVisitor<in TBase>, IFuncVisitor<in TBase, TResult>   -  允许您注册 Action<T>, Func<T, TResult> 在具体类型上 

    public interface IFuncVisitor<in TBase, TResult>
        where TBase : class
    {
        /// <summary>
        /// Register action on <see cref="T"/>.
        /// </summary>
        /// <typeparam name="T">Concrete type.</typeparam>
        /// <param name="action">Action.</param>
        void Register<T>(Func<T, TResult> action)
            where T : TBase;

        /// <summary>
        /// Visit concrete type.
        /// </summary>
        /// <param name="value">Type to visit.</param>
        /// <returns>Result value.</returns>
        TResult Visit<T>(T value)
            where T : TBase;
    }
    public interface IActionVisitor<in TBase>
        where TBase : class
    {
        /// <summary>
        /// Register action on <see cref="T"/>.
        /// </summary>
        /// <typeparam name="T">Concrete type.</typeparam>
        /// <param name="action">Action.</param>
        void Register<T>(Action<T> action)
            where T : TBase;

        /// <summary>
        /// Visit concrete type.
        /// </summary>
        /// <param name="value">Type to visit.</param>
        void Visit<T>(T value)
            where T : TBase;
    } 

Visitor - 用于 IFuncVisitor<in TBase, TResult>, IActionVisitor<in TBase> 访问者的工厂。

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

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

        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);
            }
        }
    } 

结论 

暂时就这些,希望您喜欢,请花时间发表评论。感谢您阅读本文。 

历史 

  • 2013年3月17日:初始版本。
  • 2013年5月3日:添加了基于Type的访问者
动态访问者模式 - CodeProject - 代码之家
© . All rights reserved.