AOP:使用命令模式实现AOP

2022-07-05 14:29:11 浏览数 (1)

背景

某位大牛说过,采用命名模式的好处是,你可以将命令按照不同的方式执行,如:排队、异步、远程和拦截等等。今天我介绍一下如何拦截命令的执行,这有些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

0 人点赞