.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. mongodb因为上一次异常关闭导致锁死,连接失败

    之前一直可以用,但是突然在启动node,服务端的时候报错,(下面的错误信息都是复制的网上的报错信息,刚才忘记截图错误信息了,现在已经解决问题) 这是服务端的报错 (node:17453) Unhand ...

  2. abp框架Excel导出——基于vue

    abp框架Excel导出--基于vue 目录 abp框架Excel导出--基于vue 1.技术栈 1.1 前端采用vue,官方提供 1.2 后台是abp--aspnetboilerplate 2. E ...

  3. 老男孩武老师的Django笔记

    武老师的 Django 博客笔记 基础篇 https://www.cnblogs.com/wupeiqi/articles/5237704.html 进阶篇 https://www.cnblogs.c ...

  4. PHP fclose() 函数

    定义和用法 fclose() 函数关闭打开的文件. 该函数如果成功则返回 TRUE,如果失败则返回 FALSE. 语法 fclose(file) 参数 描述 file 必需.规定要关闭的文件. 实例 ...

  5. PHP link() 函数

    定义和用法 link() 函数创建一个从指定名称连接的现存目标文件开始的硬连接. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 link(target,link) 参数 描述 ...

  6. vjudge CountTables/2018雅礼集训 方阵 dp 斯特林反演

    LINK:CountTables 神题! 首先单独考虑行不同的情况 设\(f_i\)表示此时有i列且 行都不同. 那么显然有 \(f_i=(c^i)^\underline{n}\) 考虑设\(g_i\ ...

  7. 谁说Cat不能做链路跟踪的,给我站出来

    背景 链路跟踪,我们有很多可选项.常见的有 zipkin,pinpoint,skywalking,jaeger 等. 基本上都是根据谷歌的<Dapper 大规模分布式系统的跟踪系统>这篇论 ...

  8. 7月15日考试 题解(链表+状压DP+思维题)

    前言:蒟蒻太弱了,全打的暴力QAQ. --------------------- T1 小Z的求和 题目大意:求$\sum\limits_{i=1}^n \sum\limits_{j=i}^n kth ...

  9. SpringMvc异常处理和SpringMvc拦截器

    1. 异常处理思路 Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进 行异常的处理. SpringMVC的异 ...

  10. SpringMVC入门和常用注解

    SpringMVC的基本概念 关于 三层架构和 和 MVC 三层架构 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就 是浏览器服务器.在 ...