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

Intro

前段时间我们介绍了23种设计模式,今天来分享一下 asp.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 各自实现了自己的迭代器,感兴趣可以去看下源码

More

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

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

以上均是个人理解,如果有错误还望指出,十分感谢

Reference

.net core 中的经典设计模式的应用的更多相关文章

  1. Java中23种经典设计模式详解

    Java中23种设计模式目录1. 设计模式 31.1 创建型模式 41.1.1 工厂方法 41.1.2 抽象工厂 61.1.3 建造者模式 101.1.4 单态模式 131.1.5 原型模式 151. ...

  2. 如何在C#/.NET Core中使用责任链模式

    原文:Chain Of Responsbility Pattern In C#/.NET Core 作者:Wade 译者:Lamond Lu 最近我有一个朋友在研究经典的"Gang Of F ...

  3. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  4. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  5. 如何在ASP.NET Core中应用Entity Framework

    注:本文提到的代码示例下载地址> How to using Entity Framework DB first in ASP.NET Core 如何在ASP.NET Core中应用Entity ...

  6. ASP.NET Core 中的依赖注入 [共7篇]

    一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了 ...

  7. iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  8. GoF的23个经典设计模式

    以文本和思维导图的方式简明扼要的介绍了GoF的23个经典设计模式,可当成学习设计模式的一个小手册,偶尔看一下,说不定会对大师的思想精髓有新的领悟. GoF(“四人帮”,又称Gang of Four,即 ...

  9. NET Core 中的依赖注入

    NET Core 中的依赖注入 [共7篇] 一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制, ...

随机推荐

  1. 呕心搜集总结的15个“swoole”常见问题(一)

    一.升级Swoole版本 可以使用 pecl 进行安装和升级 pecl upgrade swoole 也可以直接从 github/gitee/pecl 下载一个新版本,重新安装编译. 更新 Swool ...

  2. SUM and COUNT -- SQLZOO

    SUM and COUNT 注意:where语句中对表示条件的需要用单引号, 下面的译文使用的是有道翻译如有不正确,请直接投诉有道 01.Show the total population of th ...

  3. PHP asort() 函数

    ------------恢复内容开始------------ 实例 对关联数组按照键值进行升序排序: <?php$age=array("Peter"=>"35 ...

  4. PHP sizeof() 函数

    实例 返回数组中元素的数目: <?php$cars=array("Volvo","BMW","Toyota");echo sizeof ...

  5. Python 字典(Dictionary) cmp()方法

    Python 字典(Dictionary) cmp()方法 描述 Python 字典的 cmp() 函数用于比较两个字典元素.高佣联盟 www.cgewang.com 语法 cmp()方法语法: cm ...

  6. PHP strtotime() 函数

    ------------恢复内容开始------------ 实例 将任何字符串的日期时间描述解析为 Unix 时间戳: <?php // 设置时区 date_default_timezone_ ...

  7. 5.21 省选模拟赛 luogu P4207 [NOI2005]月下柠檬树 解析几何 自适应辛普森积分法

    LINK:月下柠檬树 之前感觉这道题很鬼畜 实际上 也就想到辛普森积分后就很好做了. 辛普森积分法的式子不再赘述 网上多的是.值得一提的是 这道题利用辛普森积分法的话就是一个解析几何的问题 而并非计算 ...

  8. 网络安全 - SSL/TLS协议运行机制的概述

    大学时也系统学过相关的网络安全,但那时并没有理论联系实践,稀里糊涂的,现在才意识到所学的东西都是好东西,可惜已晚. 来自http://www.ruanyifeng.com/blog/2014/02/s ...

  9. [转]Springboot项目的接口防刷的实例

    来源:微信公众号 马士兵 原地址:https://mp.weixin.qq.com/s/tHQcWwIt4c41IUnvCQ2QWA 说明:使用了注解的方式进行对接口防刷的功能,非常高大上,本文章仅供 ...

  10. 70道Spring面试题

    1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring 框架目标是简化Jav ...