• .net core 中的经典设计模式的应用


    .net core 中的经典设计模式的应用

    Intro

    前段时间我们介绍了23种设计模式,今天来分享一下 .net core 源码中我觉得比较典型的设计模式的应用

    实例

    责任链模式

    asp.net core 中间件的设计就是责任链模式的应用和变形,

    每个中间件根据需要处理请求,并且可以根据请求信息自己决定是否传递给下一个中间件,我也受此启发,封装了一个 PipelineBuilder 可以轻松构建中间件模式代码,可以参考这篇文章 https://www.cnblogs.com/weihanli/p/12700006.html

    中间件示例:

    app.UseStaticFiles();
    
    app.UseResponseCaching();
    app.UseResponseCompression();
    
    app.UseRouting();
    
    app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
    
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapControllerRoute(name: "areaRoute", "{area:exists}/{controller=Home}/{action=Index}");
        endpoints.MapDefaultControllerRoute();
    });
    

    PipelineBuilder 实际示例:

    var requestContext = new RequestContext()
    {
        RequesterName = "Kangkang",
        Hour = 12,
    };
    
    var builder = PipelineBuilder.Create<RequestContext>(context =>
            {
                Console.WriteLine($"{context.RequesterName} {context.Hour}h apply failed");
            })
            .Use((context, next) =>
            {
                if (context.Hour <= 2)
                {
                    Console.WriteLine("pass 1");
                }
                else
                {
                    next();
                }
            })
            .Use((context, next) =>
            {
                if (context.Hour <= 4)
                {
                    Console.WriteLine("pass 2");
                }
                else
                {
                    next();
                }
            })
            .Use((context, next) =>
            {
                if (context.Hour <= 6)
                {
                    Console.WriteLine("pass 3");
                }
                else
                {
                    next();
                }
            })
        ;
    var requestPipeline = builder.Build();
    foreach (var i in Enumerable.Range(1, 8))
    {
        Console.WriteLine();
        Console.WriteLine($"--------- h:{i} apply Pipeline------------------");
        requestContext.Hour = i;
        requestPipeline.Invoke(requestContext);
        Console.WriteLine("----------------------------");
        Console.WriteLine();
    }
    

    建造者模式

    asp.net core 中的各种 BuilderHostBuilder/ConfigurationBuilder 等,这些 Builder 大多既是 Builder 又是 Director,Builder 本身知道如何构建最终的 Product(Host/Configuration)

    var host = new HostBuilder()
        .ConfigureAppConfiguration(builder =>
        {
            // 注册配置
            builder
                .AddInMemoryCollection(new Dictionary<string, string>()
                {
                    {"UserName", "Alice"}
                })
                .AddJsonFile("appsettings.json")
                ;
        })
        .ConfigureServices((context, services) =>
        {
            // 注册自定义服务
            services.AddSingleton<IIdGenerator, GuidIdGenerator>();
            services.AddTransient<IService, Service>();
            if (context.Configuration.GetAppSetting<bool>("XxxEnabled"))
            {
                services.AddSingleton<IUserIdProvider, EnvironmentUserIdProvider>();
            }
        })
        .Build()
        ;
    

    工厂模式

    依赖注入框架中有着大量的工厂模式的代码,注册服务的时候我们可以通过一个工厂方法委托来获取服务实例,

    依赖注入的本质就是将对象的创建交给 IOC 容器来处理,所以其实 IOC 容器本质就是一个工厂,从 IOC 中获取服务实例的过程就是工厂创建对象的过程,只是会根据服务的生命周期来决定是创建新对象还是返回已有对象。

    services.AddSingleton(sp => new Svc2(sp.GetRequiredService<ISvc1>(), "xx"));
    

    单例模式

    在 dotnet 中有一个 TimeQueue 的类型,纯正的饿汉模式的单例模式代码

    class TimerQueue
    {
        #region singleton pattern implementation
    
        // The one-and-only TimerQueue for the AppDomain.
        static TimerQueue s_queue = new TimerQueue();
    
        public static TimerQueue Instance
        {
            get { return s_queue; }
        }
    
        private TimerQueue()
        {
            // empty private constructor to ensure we remain a singleton.
        }
    
        #endregion
    
        // ...
    }
    

    https://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs,49

    在 dotnet 源码中还有一些懒汉式的单例模式

    使用 Interlocked 原子操作

    internal class SimpleEventTypes<T>
        : TraceLoggingEventTypes
    {
        private static SimpleEventTypes<T> instance;
    
        internal readonly TraceLoggingTypeInfo<T> typeInfo;
    
        private SimpleEventTypes(TraceLoggingTypeInfo<T> typeInfo)
            : base(
                typeInfo.Name,
                typeInfo.Tags,
                new TraceLoggingTypeInfo[] { typeInfo })
        {
            this.typeInfo = typeInfo;
        }
    
        public static SimpleEventTypes<T> Instance
        {
            get { return instance ?? InitInstance(); }
        }
    
        private static SimpleEventTypes<T> InitInstance()
        {
            var newInstance = new SimpleEventTypes<T>(TraceLoggingTypeInfo<T>.Instance);
            Interlocked.CompareExchange(ref instance, newInstance, null);
            return instance;
        }
    }
    

    另外一个示例,需要注意,下面这种方式不能严格的保证只会产生一个实例,在并发较高的情况下可能不是同一个实例,这也可以算是工厂模式的一个示例

    static internal class ConfigurationManagerHelperFactory 
    {
        private const string ConfigurationManagerHelperTypeString = "System.Configuration.Internal.ConfigurationManagerHelper, " + AssemblyRef.System;
    
        static private volatile IConfigurationManagerHelper s_instance;
    
        static internal IConfigurationManagerHelper Instance {
            get {
                if (s_instance == null) {
                    s_instance = CreateConfigurationManagerHelper();
                }
    
                return s_instance;
            }
        }
    
        [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.MemberAccess)]
        [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Hard-coded to create an instance of a specific type.")]
        private static IConfigurationManagerHelper CreateConfigurationManagerHelper() {
            return TypeUtil.CreateInstance<IConfigurationManagerHelper>(ConfigurationManagerHelperTypeString);
        }
    }
    

    原型模式

    dotnet 中有两个数据结构 Stack/Queue 这两个数据都实现了 ICloneable 接口,内部实现了深复制
    来看 StackClone 方法实现:

    public virtual Object Clone()
    {
        Contract.Ensures(Contract.Result<Object>() != null);
     
        Stack s = new Stack(_size);
        s._size = _size;
        Array.Copy(_array, 0, s._array, 0, _size);
        s._version = _version;
        return s;
    }
    

    详细可以参考: https://referencesource.microsoft.com/#mscorlib/system/collections/stack.cs,6acda10c5f8b128e

    享元模式

    string intern(字符串池),以及 Array.Empty<int>()/Array.Empty<string>()

    策略模式

    asp.net core 中的认证和授权,我觉得就是策略模式的应用,在使用 [Authorize] 的时候会使用默认的 policy,也可以指定要使用的策略 [Authorize("Policy1")] 这样就会使用另外一种策略 Policy1,policy 还是比较简单的

    policy 是用来根据用户的认证信息来控制授权访问的,而认证则是根据当前上下文(请求上下文、线程上下文、环境上下文等)的信息进行认证从而获取用户信息的过程

    而不同的认证模式(Cookie/JWT/自定义Token等)其实是不同的处理方法,也就是策略模式中不同的算法实现,指定哪种认证模式,就是使用哪种算法实现来获取用户信息

    观察者模式

    常使用事件(event)进行解耦,外部代码通过订阅事件来解耦,实现对内部状态的观察

    Process 类中有很多事件,可以用来捕获另一个进程中的输出,错误等

    public event DataReceivedEventHandler OutputDataReceived;
    
    public event DataReceivedEventHandler ErrorDataReceived;
    

    通常这两个事件我们就可以获取到另外一个进程中的输出信息,除此之外还有很多的类在使用事件,相信你也用过很多

    组合模式

    WPF、WinForm 中都有控件的概念,这些控件的设计属于是组合模式的应用,所有的控件都会继承于某一个共同的基类, 使得单个对象和组合对象都可以看作是他们共同的基类对象

    迭代器模式

    c# 中定义了迭代器模式,原始定义:

    // 聚集抽象
    public interface IEnumerable
    {
        /// <summary>Returns an enumerator that iterates through a collection.</summary>
        /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
        IEnumerator GetEnumerator();
    }
    
    // 迭代器抽象
    public interface IEnumerator
    {
        /// <summary>Advances the enumerator to the next element of the collection.</summary>
        /// <returns>
        /// <see langword="true" /> if the enumerator was successfully advanced to the next element; <see langword="false" /> if the enumerator has passed the end of the collection.</returns>
        /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
        bool MoveNext();
    
        /// <summary>Gets the element in the collection at the current position of the enumerator.</summary>
        /// <returns>The element in the collection at the current position of the enumerator.</returns>
        object Current { get; }
    
        /// <summary>Sets the enumerator to its initial position, which is before the first element in the collection.</summary>
        /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
        void Reset();
    }
    

    Array 和 List 各自实现了自己的迭代器,感兴趣可以去看下源码

    适配器模式

    之前介绍的适配器模式中有提到 asp.net core 3.x 里引入了 ServiceProviderFactory, 使得 .net core 可以更方便的集成第三方的依赖注入框架,这里使用了适配器模式通过 ServiceFactoryAdapter 来适配各种不同的第三方的依赖注入框架

    More

    .net core 中的设计模式应用还有很多,不仅上面提到的这几个模式,也不仅仅是我所提到的这几个地方

    上面有一些示例是直接用的 dotnet framework 中的源码,因为有很多代码都是类似的,用的 https://referencesource.microsoft.com 的源码

    以上均是个人理解,如果有错误还望指出,十分感谢,欢迎补充更多设计模式应用的源码实例

    Reference

  • 相关阅读:
    java数据库连接池dbcp的使用
    图片轮显效果大全
    W5500问题集锦(持续更新中)
    Gamma校正及其OpenCV实现
    GlusterFS源代码解析 —— GlusterFS 日志
    cocos2dx 以子弹飞行为例解说拖尾效果类CCMotionStreak
    leetcode__Convert Sorted List to Binary Search Tree
    昨天面试新浪 java试题
    linux概念之性能调优
    Java实现 黑洞数
  • 原文地址:https://www.cnblogs.com/weihanli/p/13518350.html
Copyright © 2020-2023  润新知