.net core 中的經典設計模式的應用
阿新 • • 發佈:2020-08-23
# .net core 中的經典設計模式的應用
## Intro
前段時間我們介紹了23種設計模式,今天來分享一下 .net core 原始碼中我覺得比較典型的設計模式的應用
## 例項
### 責任鏈模式
asp.net core 中介軟體的設計就是責任鏈模式的應用和變形,
每個中介軟體根據需要處理請求,並且可以根據請求資訊自己決定是否傳遞給下一個中介軟體,我也受此啟發,封裝了一個 `PipelineBuilder` 可以輕鬆構建中介軟體模式程式碼,可以參考這篇文章
中介軟體示例:
``` csharp
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` 實際示例:
``` csharp
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 中的各種 `Builder`, `HostBuilder`/`ConfigurationBuilder` 等,這些 `Builder` 大多既是 Builder 又是 Director,Builder 本身知道如何構建最終的 `Product`(`Host`/`Configuration`)
``` csharp
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 中獲取服務例項的過程就是工廠建立物件的過程,只是會根據服務的生命週期來決定是建立新物件還是返回已有物件。
``` csharp
services.AddSingleton(sp => new Svc2(sp.GetRequiredService(), "xx"));
```
### 單例模式
在 dotnet 中有一個 `TimeQueue` 的型別,純正的餓漢模式的單例模式程式碼
``` csharp
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
// ...
}
```
在 dotnet 原始碼中還有一些懶漢式的單例模式
使用 `Interlocked` 原子操作
``` csharp
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;
}
}
```
另外一個示例,需要注意,下面這種方式不能嚴格的保證只會產生一個例項,在併發較高的情況下可能不是同一個例項,這也可以算是工廠模式的一個示例
``` csharp
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` 介面,內部實現了深複製
來看 `Stack` 的 `Clone` 方法實現:
``` csharp
public virtual Object Clone()
{
Contract.Ensures(Contract.Result