博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.net core 中的经典设计模式的应用
阅读量:4034 次
发布时间:2019-05-24

本文共 7923 字,大约阅读时间需要 26 分钟。

.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
(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
() { {"UserName", "Alice"} }) .AddJsonFile("appsettings.json") ; }) .ConfigureServices((context, services) => { // 注册自定义服务 services.AddSingleton
(); services.AddTransient
(); if (context.Configuration.GetAppSetting
("XxxEnabled")) { services.AddSingleton
(); } }) .Build() ;

工厂模式

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

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

services.AddSingleton(sp => new Svc2(sp.GetRequiredService
(), "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
: TraceLoggingEventTypes{ private static SimpleEventTypes
instance; internal readonly TraceLoggingTypeInfo
typeInfo; private SimpleEventTypes(TraceLoggingTypeInfo
typeInfo) : base( typeInfo.Name, typeInfo.Tags, new TraceLoggingTypeInfo[] { typeInfo }) { this.typeInfo = typeInfo; } public static SimpleEventTypes
Instance { get { return instance ?? InitInstance(); } } private static SimpleEventTypes
InitInstance() { var newInstance = new SimpleEventTypes
(TraceLoggingTypeInfo
.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
(ConfigurationManagerHelperTypeString); }}

原型模式

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

public virtual Object Clone(){    Contract.Ensures(Contract.Result() != 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{    /// Returns an enumerator that iterates through a collection.    /// 
An
object that can be used to iterate through the collection.
IEnumerator GetEnumerator();}// 迭代器抽象public interface IEnumerator{ /// Advances the enumerator to the next element of the collection. ///
///
if the enumerator was successfully advanced to the next element;
if the enumerator has passed the end of the collection.
///
The collection was modified after the enumerator was created.
bool MoveNext(); /// Gets the element in the collection at the current position of the enumerator. ///
The element in the collection at the current position of the enumerator.
object Current { get; } /// Sets the enumerator to its initial position, which is before the first element in the collection. ///
The collection was modified after the enumerator was created.
void Reset();}

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

More

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

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

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

Reference

  • https://github.com/dotnet/aspnetcore

  • https://github.com/dotnet/extensions

  • https://github.com/dotnet/corefx

  • https://github.com/dotnet/aspnetcore

  • https://github.com/dotnet/runtime

你可能感兴趣的文章
慢慢欣赏linux kbuild的一些技巧
查看>>
慢慢欣赏linux kbuild如何编译c和汇编
查看>>
C对象化
查看>>
慢慢欣赏linux 生成内核镜像
查看>>
慢慢欣赏linux 内核反汇编分析
查看>>
慢慢欣赏linux 内核的重定位
查看>>
慢慢欣赏linux elf文件
查看>>
linux内核学习(3)建立页式内存映射
查看>>
linux内核学习(2)建立段式内存映射
查看>>
linux内核学习(7)脱胎换骨解压缩的内核
查看>>
以太网基础知识
查看>>
慢慢欣赏linux 内核模块引用
查看>>
kprobe学习
查看>>
慢慢欣赏linux phy驱动初始化2
查看>>
慢慢欣赏linux CPU占用率学习
查看>>
2020年终总结
查看>>
linux内核学习(4)建立正式内核的页式内存映射, 以x86 32位模式为例
查看>>
慢慢欣赏linux 查看硬盘情况
查看>>
慢慢欣赏linux vsftpd的使用
查看>>
慢慢欣赏linux 进程哈希表
查看>>