动态访问者模式






4.55/5 (17投票s)
访问者设计模式 - 动态实现。
引言
访问者“代表对对象结构元素执行的操作。访问者允许您定义新的操作,而无需更改其操作的元素的类” (GoF).
我相信您了解访问者设计模式,因此这里介绍动态实现。动态访问者将模式与业务逻辑分开。访问者模式基于双重分派,因此我们应该实现运行时分派。例如,我们可以通过dynamic
或Type
来实现这一点。
所有示例中都使用了以下类层次结构
基于“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
的访问者