• 热门专题

Middleware的艺术

作者:jiulang  发布日期:2016-01-05 19:28:48
Tag标签:艺术  
  • 定义

    Middleware直译叫中间件,目前在百度上很难找到一个简单明了的含义解释,.Net下以前也比较难以看到它的身影,但在Microsoft.Owin里,多个地方都看到MiddleWare,我近来在尝试理解Middleware,并在实际中模仿应用,本文章将我的个人理解和大家分享一下。

    Middleware的抽象

    Microsoft.Owin的Middleware

    public abstract class OwinMiddleware
    {
        protected OwinMiddleware(OwinMiddleware next);
    
        protected OwinMiddleware Next { get; set; }
    
        public abstract Task Invoke(IOwinContext context);
    }

    微软把Middleware定义在抽象类,除了Invoke的中间件执行入口,还有一个Next的中间件属性,两者都是非常抽象。Invoke正是本中间件的处理逻辑,参数IOwinContext包含问题试卷和答题卡,Next表示下一个中间件,如果本中间件不想解决此问题,那么就让Next来解决这个问题,以此类推。提问题的人不用关注是谁回答了问题,他只关注答案了够了。

    简单的Middleware接口

    如果我们把中间件定义为接口,那么一个简单的中间件接口可以如下:

    public interface IMiddleware
    {
        IMiddleware Next { set; }
        Answer GetAnswer(Question question);
    }

    当然,在一些实际项目中,中间件的抽象程度不一样,所以中间件的执行方法是根据实际需要作合理的设计,但Next一般不会有变化,它都是代表下一个中间件。

    Middleware和插件的区别

    插件是应用程序的功能扩展,它可以只关注自身的功能的实现,它可能不是带问题的,但各插件的执行接口是一样的,最简单的插件接口可以如下:

    public interface IPlug
    {
        // 加载执行插件
        void Init();
    }

    Middleware是问题解决单元抽象,它往往是由多个单元同时协同工作,各单元虽然没有直接关系,但Next属性还是得到了下个中间件的实例,提供给本中间件来传递。Middlware随着数量的增多,解决的问题各类也可以越多,和插件越多功能越丰富有相似。

    Middleware的使用场景

    我曾经写过《.Net下一个类型转换神器》,近期在代码重构,发现这玩意很适合使用中间件来实现。在类型转换中,调用者想要的是这种:

    /// <summary>
    /// 将value转换为目标类型
    /// </summary>
    /// <param name="value">要转换的值</param>
    /// <param name="targetType">转换的目标类型</param>
    /// <returns></returns>
    object Convert(object value, Type targetType);

    value和targetType千变万化,一口可吃不完,本着单一职责原则,我们应该要写很多转换单元,每个单元只负责一种类型转换,转换器由N多个转换单元组成,如果转换单元是中间件,抽象的中间件接口应该如下:

        /// <summary>
        /// 定义类型转换单元的接口
        /// </summary>
        public interface IConvertMiddleware
        {
            /// <summary>
            /// 设置下一个转换单元
            /// </summary>
            IConvertMiddleware Next { set; }
    
            /// <summary>
            /// 将value转换为目标类型
            /// </summary>
            /// <param name="上下文">context</param>
            /// <returns></returns>
            object Convert(ConvertContext context);
        }

    实际当中,我们可能未必需要这么抽象,我的实际接口是

        /// <summary>
        /// 定义类型转换单元的接口
        /// </summary>
        public interface IConvert
        {
            /// <summary>
            /// 设置转换器
            /// </summary>
            Converter Converter { set; }
    
            /// <summary>
            /// 设置下一个转换单元
            /// </summary>
            IConvert NextConvert { set; }
    
            /// <summary>
            /// 将value转换为目标类型
            /// </summary>
            /// <param name="value">要转换的值</param>
            /// <param name="targetType">转换的目标类型</param>
            /// <returns></returns>
            object Convert(object value, Type targetType);
        }

    然后,我们来一个一个地来实现转换单元:

    某个单元的实现如下:

        /// <summary>
        /// 表示不作转换的转换单元
        /// </summary>
        public class NoConvert : IConvert
        {
            /// <summary>
            /// 转换器实例
            /// </summary>
            public Converter Converter { get; set; }
    
            /// <summary>
            /// 下一个转换单元
            /// </summary>
            public IConvert NextConvert { get; set; }
    
            /// <summary>
            /// 将value转换为目标类型
            /// </summary>
            /// <param name="value">要转换的值</param>
            /// <param name="targetType">转换的目标类型</param>
            /// <returns></returns>
            public object Convert(object value, Type targetType)
            {
                if (targetType == typeof(object))
                {
                    return value;
                }
    
                if (value != null && targetType == value.GetType())
                {
                    return value;
                }
    
                return this.NextConvert.Convert(value, targetType);
            }
        }
    NoConvert

    更广泛的Middleware

    我近来在开发开源项目《NetworkSocket》,自从看到Microsoft.Owin之后的中间件之后,觉得Middleware可以在很多领域中使用,现在这个项目里的协议解析实现者都已经完全由中间件来开发,功能越来丰富,但复杂度感觉没有增大。看看下面代码,你应该能感觉到Middleware的甜味。

    var listener = new TcpListener();
    listener.Use<HttpMiddleware>();
    listener.Use<JsonWebSocketMiddleware>();
    listener.Use<FastMiddleware>();            
    listener.Start(1212);

延伸阅读:

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规