zoukankan      html  css  js  c++  java
  • AOP:使用命令模式实现AOP

    背景

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

    思路

    就是一个管道过滤器而已

    实现

    先不考虑处理器的实例化和过滤器列表的实例化,如果给你一个命令、一些过滤器和一个处理器,让你组装为一个管道应该不是啥大问题。

    这部分概念虽然简单,可是也不见得好理解,因此我基本把全部代码都贴上了,建议不太明白的同学,自己重写一遍,加深对管道过滤器的理解。

    核心代码

    命令接口

     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 }

    命令处理器接口,一个命令只能有一个命令处理器。

     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 }

    命令拦截器,拦截正在被执行的命令。

     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 }

    命令执行上下文接口,代表了一次命令的执行过程。

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

    管道过滤器的内部实现

     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 }

    命令服务,负责执行命令

     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 }

    事务拦截器

     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 }

    应用事务拦截器

     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 }

    执行命令

     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本质上也是消息模式,他们也内置了管道过滤器模式。

  • 相关阅读:
    莫比乌斯反演学习笔记
    NOIp 2020 游记
    题解【LOJ3087】「GXOI / GZOI2019」旅行者
    题解【CF999E】Reachability from the Capital
    题解【LOJ2007】「SCOI2015」国旗计划
    题解【LOJ3145】「APIO2019」桥梁
    题解【LOJ2114】「HNOI2015」菜肴制作
    CSP-J/S 2020 爆炸记
    题解【洛谷P2569】[SCOI2010]股票交易
    补题目录
  • 原文地址:https://www.cnblogs.com/happyframework/p/3120410.html
Copyright © 2011-2022 走看看