【轮子狂魔】轮子的魅力之扩展能力

序言

如果你是第一次看本文,建议先看下前面两篇,否则你可能会一头雾水

看过上一篇【轮子狂魔】打造简易无配置的IoC的人,可能会有几个疑问,我统一回答一下吧。

1.你这说是IoC,但感觉不像啊。

   首先,我在百度百科里把IoC的概念Copy过来看看。

   控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。

    那么,IoC一定是AutoFac、Unity之类的吗?它什么时候被标签上一定要与这些第三方功能一致的标签?

    在我上篇文中,我使用的是参数注入,缓存反射关系的依赖查找方式。所以我说是简易的IoC应该没什么问题。

2.有人在上一篇看到了CQRS或者DDD的影子。

    实话说我最近确实看过这方面的东西,受到了一些启发,所以命名上有点贴近这方面技术名词,但这仅仅是名字相近而已。

3.为什么要出这样一个系列?

    我希望我可以从因果关系上解释出遇到什么样的问题,可以有什么样的方法应对,或者以什么样的顺序来搭建我们的系统架构,这并不是一个标准,而是个人的经验,仅供参考而已。

    另外我也希望大家可以扩展思维,发现架构是可以“造”出来的,而不是“拷贝”出来的,不要落入三层、MVC、MVVM、SOA等里面。

 

改造,让架构更智能

开发微信时发现一个可以提炼出来的共同点:交互接口参数中需携带AccessToken

而这个AccessToken有多么烦人,在上一篇已经提过我就不再赘述了。

 

IAccessTokenAuth的由来

我们要做的是让架构可以帮助我们自动填充这个AccessToken,那我们就先给他定义为一个接口,方便后面去针对接口操作,

同时,Event是穿梭在Event、Dispatch、Command三个层中,所以最适合的地方就是在事件里,而接口也是由各个事件自己去实现。

 

1     /// <summary>
2     /// 微信接口交互凭据授权接口
3     /// </summary>
4     public interface IAccessTokenAuth
5     {
6         string AccessToken { get; set; }
7     }
View Code

 

DispatchBeforeActiveHandler的由来

我们要想清楚这个接口需要在什么时候执行?

就以当前的业务来说,肯定是在执行微信指令之前填充。

所以执行顺序当然是在普通的调度处理器执行前,为了统一执行方式,我们也需要把这个看作是一个调度处理器,只是执行顺序特殊一些。

因为调度器建立关系网是根据特性(Attribute)来的,我们就让这个特殊的调度器继承自DispatchHandlerAttribute的类

  

1     [AttributeUsage(AttributeTargets.Method)]
2     public class DispatchBeforeActiveHandlerAttribute : DispatchHandlerAttribute 3  { 4 public DispatchBeforeActiveHandlerAttribute() 5 : base(typeof(DispatchHandlerAttribute)) 6  { 7 8  } 9 }
View Code

 

如何使用IAccessTokenAuth?

以创建菜单为例

1     /// <summary>
2     /// 创建菜单事件
3     /// </summary>
4     public class CreateMenuEvent : DispatchEvent, IAccessTokenAuth
5     {
6         public string AccessToken { get; set; }
7 
8         public MenuList MenuList { get; set; }
9     }
View Code

 

如何使用DispatchBeforeActiveHandler?

 根据业务分类,我们把FillAccessToken方法加到AccessTokenCommand类中

 1     /// <summary>
 2     /// 微信交互接口凭证命令  3 /// </summary>  4 public class AccessTokenCommand  5  {  6 #region 静态构造函数  7  8 static AccessTokenCommand()  9  { 10 AutoUpdateCache.Add(CacheKeySet.AccessToken.ToString(), new AutoUpdateItem() 11  { 12 UpdateValue = (AutoUpdateItem autoUpdateItem) => 13  { 14 var accessTokenInfo = CommandHelper.GetWeChatResponseObject<AccessTokenInfo>(new AccessTokenCommandRequest()); 15 16 autoUpdateItem.ExpiredSeconds = accessTokenInfo.ExpiresIn - 30;//预留过期时效,防止提前过期 17 autoUpdateItem.Value = accessTokenInfo; 18  } 19  }); 20  } 21 22 /// <summary> 23 /// 填充微信接口交互凭据 24 /// </summary> 25 /// <param name="e"></param> 26  [DispatchBeforeActiveHandler()] 27 public void FillAccessToken(DispatchEvent e) 28  { 29 IAccessTokenAuth accessTokenAuth = e as IAccessTokenAuth; 30 if (accessTokenAuth == null) 31  { 32 return; 33  } 34 35 var getAccessTokenEvent = new GetAccessTokenEvent(); 36  Dispatcher.ActiveEvent(getAccessTokenEvent); 37 38 accessTokenAuth.AccessToken = getAccessTokenEvent.AccessTokenInfo.AccessToken; 39  } 40 41 #endregion 42 43 /// <summary> 44 /// 获取微信交互接口凭证 45 /// </summary> 46 /// <param name="e"></param> 47 [DispatchHandler(typeof(GetAccessTokenEvent))] 48 public void GetAccessToken(GetAccessTokenEvent e) 49  { 50 e.AccessTokenInfo = AutoUpdateCache.GetValue<AccessTokenInfo>(CacheKeySet.AccessToken.ToString()); 51  } 52 }
View Code

我们看到FillAccessToken有一个参数DispatchEvent,一个原因是我们需要为这个事件内的AccessToken赋值,还有一个原因是它是一个基类,这样我们就可以处理任何的事件。

另外FillAccessToken判断DispatchEvent是不是IAccessTokenAuth接口,来判断是否需要填充AccessToken。

为什么是做在这里而不是在调度器?因为调度器尽量保持中立,不要接触过于细节的业务逻辑,所以放在这里来校验是否需要填充AccessToken更合适。

 

如何让调度器支持DispatchBeforeActiveHandler?

 1.添加一个激活前处理器列表

 2.建立关系网时,分开处理DispatchBeforeActiveHandler和DispatchHandler

 3.在ActiveEvent方法中,执行DispatchHandler之前,先循环遍历DispatchBeforeActiveHandler

  1     /// <summary>
  2     /// 调度器
  3     /// </summary>
  4     public class Dispatcher
  5     {
  6         /// <summary>
  7         /// 调度关系网
  8         /// </summary>
  9         private static Dictionary<Type, List<DispatchHandlerAttribute>> _dicDispatchRelativeNetwork = new Dictionary<Type, List<DispatchHandlerAttribute>>();
 10 
 11         /// <summary>
 12         /// 激活前处理器列表
 13         /// </summary>
 14         private static List<DispatchHandlerAttribute> _lstBeforeActiveHandler = new List<DispatchHandlerAttribute>();
 15 
 16         /// <summary>
 17         /// 建立调度关系网
 18         /// </summary>
 19         /// <param name="assembly"></param>
 20         public static void BuildDispatchRelationship(Assembly assembly)
 21         {
 22             Logger.Info("调度器:开始建立调度关系网...");
 23 
 24             var types = assembly.GetTypes();
 25 
 26             foreach (var type in types)
 27             {
 28                 var methods = type.GetMethods();
 29 
 30                 foreach (var method in methods)
 31                 {
 32                     var attribute = method.GetCustomAttributes(typeof(DispatchHandlerAttribute), true).FirstOrDefault();
 33                     if (attribute != null)
 34                     {
 35                         CheckParameterRule(method);
 36 
 37                         var handler = attribute as DispatchHandlerAttribute;
 38                         handler.DispatchInstance = Activator.CreateInstance(type);
 39                         handler.ActionMethodInfo = method;
 40 
 41                         if (attribute is DispatchBeforeActiveHandlerAttribute)
 42                         {
 43                             AddBeforeActiveHandler(handler);
 44                         }
 45                         else
 46                         {
 47                             AddDispatchRelation(handler);
 48                         }
 49                     }
 50                 }
 51             }
 52         }
 53 
 54         /// <summary>
 55         /// 添加激活前处理器
 56         /// </summary>
 57         /// <param name="handler">调度处理器</param>
 58         private static void AddBeforeActiveHandler(DispatchHandlerAttribute handler)
 59         {
 60             _lstBeforeActiveHandler.Add(handler);
 61 
 62             Logger.Info(string.Format("调度器:增加激活前处理器 [{0}]-[{1}.{2}]", handler.ObservedDispatchEventType.Name, handler.DispatchInstance.GetType().Name, handler.ActionMethodInfo.Name));
 63         }
 64 
 65         /// <summary>
 66         /// 添加调度关系
 67         /// </summary>
 68         /// <param name="handler">调度处理器</param>
 69         private static void AddDispatchRelation(DispatchHandlerAttribute handler)
 70         {
 71             var eventType = handler.ObservedDispatchEventType;
 72 
 73             if (!_dicDispatchRelativeNetwork.ContainsKey(eventType))
 74             {
 75                 _dicDispatchRelativeNetwork.Add(eventType, new List<DispatchHandlerAttribute>());
 76             }
 77 
 78             _dicDispatchRelativeNetwork[eventType].Add(handler);
 79 
 80             Logger.Info(string.Format("调度器:建立新的关系网 [{0}]-[{1}.{2}]", eventType.Name, handler.DispatchInstance.GetType().Name, handler.ActionMethodInfo.Name));
 81         }
 82 
 83         /// <summary>
 84         /// 检查参数规则
 85         /// </summary>
 86         /// <param name="method"></param>
 87         private static void CheckParameterRule(MethodInfo method)
 88         {
 89             var parameters = method.GetParameters();
 90             if (parameters == null ||
 91                 parameters.Length != 1 ||
 92                 (!parameters.FirstOrDefault().ParameterType.Equals(typeof(DispatchEvent)) &&
 93                  !parameters.FirstOrDefault().ParameterType.BaseType.Equals(typeof(DispatchEvent))
 94                 ))
 95             {
 96                 throw new Exception(string.Format("DispatchHandler - [{0}]的参数必须是只有一个且继承自DispatchEvent", method.Name));
 97             }
 98         }
 99 
100         /// <summary>
101         /// 激活事件
102         /// </summary>
103         /// <param name="dispatchEvent">调度事件</param>
104         public static void ActiveEvent(DispatchEvent dispatchEvent)
105         {
106             var type = dispatchEvent.GetType();
107 
108             if (!_dicDispatchRelativeNetwork.ContainsKey(type))
109             {
110                 Logger.Error(string.Format("调度器:当前事件[{0}]没有找到绑定的Handler", type.FullName));
111                 return;
112             }
113 
114             _lstBeforeActiveHandler.ForEach(action =>
115             {
116                 ActiveAction(action, dispatchEvent);
117             });
118 
119             _dicDispatchRelativeNetwork[type].ForEach(action =>
120             {
121                 ActiveAction(action, dispatchEvent);
122             });
123         }
124 
125         private static void ActiveAction(DispatchHandlerAttribute action, DispatchEvent dispatchEvent)
126         {
127             try
128             {
129                 action.ActionMethodInfo.Invoke(action.DispatchInstance, new object[] { dispatchEvent });
130             }
131             catch (Exception ex)
132             {
133                 if (ex.InnerException != null && ex.InnerException.GetType().Equals(typeof(WCFLib.ExceptionExtension.GException)))
134                 {
135                     throw ex.InnerException;
136                 }
137                 else
138                 {
139                     throw;
140                 }
141             }
142         }
143     }
View Code

 

激活Event的代码变成什么样子?

 

1             var getAccessTokenEvent = new GetAccessTokenEvent();
2             Dispatcher.ActiveEvent(getAccessTokenEvent);
3             var accessTokenInfo = getAccessTokenEvent.AccessTokenInfo; 


是的,你没看错,没有变化!

同时,在真正的创建菜单事件中也不需要处理任何有关AccessToken的业务逻辑。

因为创建菜单的指令也很简单,我就不贴代码了,跟GetAccessToken差不多,只是处理微信指令时逻辑上不太一样而已。

 

为什么我喜欢造轮子?

 在满足技术条件的基础上,轮子的可控性更高,可扩展性也更高。

 轮子的发展方向会根据我们的业务进行调整,同时去掉了我们并不需要的一些附带功能。

 绝大多数第三方是做一个通用的类库,而我造的轮子不是,我造的是更贴近系统业务的,更贴近团队技术水平的。

 不论是从封装也好,调用也好,各个角度来看,我们都能够控制轮子的形态,让轮子成为我们非常熟悉的调用方式。学习成本会也自然就会降低。

 轮子有好有坏,看你从哪个方面来看,这个不需要去争论,我们只需要保持着可用性、可扩展性、性能达标的标准去走即可。

 最后,我并不鼓励盲目的造轮子,这是我从始至终的观点,但我仍然坚持造最适合自己的轮子,两者并不冲突。 ^_^

转载于:https://www.cnblogs.com/doddgu/p/lunzikuangmo_lunzidemeili.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值