背景
某位大牛说过,采用命名模式的好处是,你可以将命令按照不同的方式执行,如:排队、异步、远程和拦截等等。今天我介绍一下如何拦截命令的执行,这有些AOP的味道。
思路
就是一个管道过滤器而已
实现
先不考虑处理器的实例化和过滤器列表的实例化,如果给你一个命令、一些过滤器和一个处理器,让你组装为一个管道应该不是啥大问题。
这部分概念虽然简单,可是也不见得好理解,因此我基本把全部代码都贴上了,建议不太明白的同学,自己重写一遍,加深对管道过滤器的理解。
核心代码
命令接口
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Happy.Command
8 {
9 /// <summary>
10 /// 命令接口。
11 /// </summary>
12 public interface ICommand
13 {
14 }
15 }
命令处理器接口,一个命令只能有一个命令处理器。
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Happy.Command
8 {
9 /// <summary>
10 /// 命令处理器接口,一个命令只能有一个命令处理器。
11 /// </summary>
12 public interface ICommandHandler<TCommand>
13 where TCommand : ICommand
14 {
15 /// <summary>
16 /// 处理命令。
17 /// </summary>
18 void Handle(TCommand command);
19 }
20 }
命令拦截器,拦截正在被执行的命令。
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Happy.Command
8 {
9 /// <summary>
10 /// 命令拦截器,拦截正在被执行的命令。
11 /// </summary>
12 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
13 public abstract class CommandInterceptorAttribute : Attribute
14 {
15 /// <summary>
16 /// 构造方法。
17 /// </summary>
18 /// <param name="order">指示拦截器在管道中的位置</param>
19 protected CommandInterceptorAttribute(int order)
20 {
21 this.Order = order;
22 }
23
24 /// <summary>
25 /// 拦截正在被执行的命令。
26 /// </summary>
27 /// <param name="context">命令执行上下文</param>
28 public abstract void Intercept(ICommandExecuteContext context);
29
30 /// <summary>
31 /// 拦截器在管道中的位置。
32 /// </summary>
33 public int Order { get; protected set; }
34 }
35 }
命令执行上下文接口,代表了一次命令的执行过程。
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Happy.Command
8 {
9 /// <summary>
10 /// 命令执行上下文接口,代表了一次命令的执行过程。
11 /// </summary>
12 public interface ICommandExecuteContext
13 {
14 /// <summary>
15 /// 命令执行服务。
16 /// </summary>
17 ICommandService CommandService { get; }
18
19 /// <summary>
20 /// 正在执行的命令。
21 /// </summary>
22 ICommand Command { get; }
23
24 /// <summary>
25 /// 执行下一个<see cref="CommandInterceptorAttribute"/>,如果已经是最后一个,就会执行<see cref="ICommandHandler{TCommand}"/>。
26 /// </summary>
27 void ExecuteNext();
28 }
29 }
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using Happy.ExtensionMethod.Reflection;
8
9 namespace Happy.Command.Internal
10 {
11 internal sealed class CommandExecuteContext : ICommandExecuteContext
12 {
13 private CommandInterceptorChain _commandInterceptorChain;
14
15 internal CommandExecuteContext(ICommandService commandService, ICommand command, Action commandExecutor)
16 {
17 this.CommandService = commandService;
18 this.Command = command;
19 _commandInterceptorChain = new CommandInterceptorChain(
20 this,
21 command.GetType().GetAttributes<CommandInterceptorAttribute>(),
22 commandExecutor);
23 }
24
25
26 public ICommandService CommandService
27 {
28 get;
29 private set;
30 }
31
32 public ICommand Command { get; private set; }
33
34 public void ExecuteNext()
35 {
36 _commandInterceptorChain.ExecuteNext();
37 }
38 }
39 }
管道过滤器的内部实现
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Happy.Command.Internal
8 {
9 internal sealed class CommandInterceptorChain
10 {
11 private ICommandExecuteContext _commandExecuteContext;
12 private CommandInterceptorAttribute[] _commandInterceptors;
13 private Action _commandExecutor;
14 private int _currentCommandInterceptorIndex = -1;
15
16 internal CommandInterceptorChain(
17 ICommandExecuteContext commandExecuteContext,
18 CommandInterceptorAttribute[] commandInterceptors,
19 Action commandExecutor)
20 {
21 _commandExecuteContext = commandExecuteContext;
22 _commandInterceptors = commandInterceptors.OrderBy(x => x.Order).ToArray();
23 _commandExecutor = commandExecutor;
24 }
25
26 private CommandInterceptorAttribute CurrentCommandInterceptor
27 {
28 get
29 {
30 return _commandInterceptors[_currentCommandInterceptorIndex];
31 }
32 }
33
34 internal void ExecuteNext()
35 {
36 _currentCommandInterceptorIndex ;
37
38 if (_currentCommandInterceptorIndex < _commandInterceptors.Length)
39 {
40 this.CurrentCommandInterceptor.Intercept(_commandExecuteContext );
41 }
42 else
43 {
44 _commandExecutor();
45 }
46 }
47 }
48 }
命令服务,负责执行命令
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Threading;
7
8 using Common.Logging;
9 using Microsoft.Practices.ServiceLocation;
10
11 using Happy.DesignByContract;
12
13 namespace Happy.Command.Internal
14 {
15 internal sealed class DefaultCommandService : ICommandService
16 {
17 private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
18
19 public void Execute<TCommand>(TCommand command)
20 where TCommand : ICommand
21 {
22 command.MustNotNull("command");
23
24 var context = this.CreateCommandExecuteContext(command);
25
26 context.ExecuteNext();
27 }
28
29 public ICommandService AddService<T>(T service)
30 {
31 _services[typeof(T)] = service;
32
33 return this;
34 }
35
36 public T GetService<T>()
37 {
38 return (T)_services[typeof(T)];
39 }
40
41 private CommandExecuteContext CreateCommandExecuteContext<TCommand>(TCommand command)
42 where TCommand : ICommand
43 {
44
45 return new CommandExecuteContext(this, command, () =>
46 {
47 this.ExecuteCommandHandler(command);
48 });
49 }
50
51 private void ExecuteCommandHandler<TCommand>(TCommand command)
52 where TCommand : ICommand
53 {
54 ServiceLocator.Current.MustNotNull("ServiceLocator.Current");
55
56 var commandHandler = ServiceLocator
57 .Current
58 .GetInstance<ICommandHandler<TCommand>>();
59
60 commandHandler.Handle(command);
61 }
62 }
63 }
事务拦截器
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Transactions;
7
8 namespace Happy.Command
9 {
10 /// <summary>
11 /// 事务拦截器。
12 /// </summary>
13 public sealed class TransactionAttribute : CommandInterceptorAttribute
14 {
15 /// <inheritdoc />
16 public TransactionAttribute(int order) : base(order) { }
17
18 /// <inheritdoc />
19 public override void Intercept(ICommandExecuteContext context)
20 {
21 using (var ts = new TransactionScope())
22 {
23 context.ExecuteNext();
24
25 ts.Complete();
26 }
27 }
28 }
29 }
应用事务拦截器
代码语言:javascript复制 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 using Happy.Domain;
8 using Happy.Command;
9 using Happy.DesignByContract;
10
11 namespace Happy.Application
12 {
13 /// <summary>
14 /// 简单的创建命令。
15 /// </summary>
16 [Transaction(1)]
17 public abstract class SimpleCreateCommand<TAggregateRoot> : SimpleCommand<TAggregateRoot>
18 where TAggregateRoot : AggregateRoot
19 {
20 }
21 }
执行命令
代码语言:javascript复制 1 /// <summary>
2 /// 创建。
3 /// </summary>
4 public ActionResult Create(TAggregateRoot item)
5 {
6 this.CurrentCommandService.Execute(new TCreateCommand
7 {
8 Aggregate = item
9 });
10
11 return this.NewtonsoftJson(new
12 {
13 success = true,
14 items = this.GetById(item.Id)
15 });
16 }
备注
这里的命令模式本质上是一种消息模式,因为命令里没有任何行为,将行为独立了出来。像WCF、ASP.NET和ASP.NET MVC本质上也是消息模式,他们也内置了管道过滤器模式。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/110108.html原文链接:https://javaforall.cn