由于笔者时间有限,无法写更多的说明文本,且主要是自己用来记录学习点滴,请谅解,下面直接贴代码了(代码中有一些说明):
01-不好的设计
代码:
using System; namespace DesignSample { public class TrTemplateContext { public string TrAttrPrefix { get; set; } } class Program { public static void Main(string[] args) { AppendTimeForTrTag(c => string.Format("{0}-id=\"{1}\"", c.TrAttrPrefix, "tr1")); //很显然,这是一个糟糕的设计,意味着每增加一个类似 AppendTimeForTrTag 的封装就 //要增加很多类似于 AppendTimeForTrTag 的代码。参考 ASP.NET Core 中的 middleware } static void AppendTimeForTrTag(Func<TrTemplateContext, string> trTemplate) {/* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */ Func<TrTemplateContext, string> trTimeTemplate = c => string.Format("{0}-time=\"{1}\"", c.TrAttrPrefix, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); Func<TrTemplateContext, string> trAllTemplate = trTimeTemplate; if(trTemplate != null) { trAllTemplate = c => trTimeTemplate(c) + " " + trTemplate(c); } PrintTrTag(trAllTemplate); } static void PrintTrTag(Func<TrTemplateContext, string> trTemplate) {/* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */ string htmlTempl = "<tr {0}></tr>"; string trInner = null; TrTemplateContext templContext = new TrTemplateContext { TrAttrPrefix = "ng" }; if (trTemplate != null) { trInner = trTemplate(templContext); } string fullHtml = string.Format(htmlTempl, trInner); Console.WriteLine(fullHtml); } } }
运行结果:
02-中间件设计(未提取公共代码)
代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignSample { public class TrAttrTemplateContext { public string TrAttrPrefix { get; set; } private StringBuilder trAttrBuilder = new StringBuilder(); public void Add(string str) { if(trAttrBuilder.Length > 0) { trAttrBuilder.Append(" "); } trAttrBuilder.Append(str); } public string GetAllString() { return trAttrBuilder.ToString(); } } public delegate void RequestDelegate(TrAttrTemplateContext builder); public class TrAttrTemplateBuilder { private readonly List<Func<RequestDelegate, RequestDelegate>> _middlewares = new List<Func<RequestDelegate, RequestDelegate>>(); public TrAttrTemplateBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) { _middlewares.Add(middleware); return this; } public RequestDelegate Build() { _middlewares.Reverse(); RequestDelegate next = c => { }; foreach (var middleware in _middlewares) { next = middleware(next); } return next; } } class Program { public static void Main(string[] args) { PrintTrTag(app => app.Use(AppendIdForTrTag) //给 tr 标签增加 ng-id 属性 .Use(AppendTimeForTrTag) //给 tr 标签增加 ng-time 属性 ); } /* 假设本方法来自于你们公司的B部门,通过封装,用于给<tr>标签固定附加 ng-id 属性 */ static RequestDelegate AppendIdForTrTag(RequestDelegate next) => context => { context.Add($"{ context.TrAttrPrefix }-id=\"tr1\""); next(context); }; /* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */ static RequestDelegate AppendTimeForTrTag(RequestDelegate next) => context => { context.Add($"{ context.TrAttrPrefix }-time=\"{ DateTime.Now.ToString() }\""); next(context); }; /* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */ static void PrintTrTag(Func<TrAttrTemplateBuilder, TrAttrTemplateBuilder> trBuilderAction) { string htmlTempl = "<tr {0}></tr>"; string trAttrInner = null; if (trBuilderAction != null) { TrAttrTemplateBuilder builder = new TrAttrTemplateBuilder(); builder = trBuilderAction(builder); if(builder != null) { TrAttrTemplateContext templContext = new TrAttrTemplateContext { TrAttrPrefix = "ng" }; builder.Build()(templContext); trAttrInner = templContext.GetAllString(); } } string fullHtml = string.Format(htmlTempl, trAttrInner); Console.WriteLine(fullHtml); } } }
运行截图:和 上图一样。
03-中间件设计(已提取公共代码)
代码:
SpaceMiddlewareBuilder.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DesignSample { /// <summary> /// 空格中间件生成器 /// </summary> /// <typeparam name="TDelegate">委托的类型</typeparam> public class SpaceMiddlewareBuilder<TDelegate, TDelegateParam, TChild> where TDelegate: Delegate where TDelegateParam: SpaceMiddlewareContext where TChild : SpaceMiddlewareBuilder<TDelegate, TDelegateParam, TChild>,new() { private readonly List<Func<TDelegate, TDelegate>> _middlewares = new List<Func<TDelegate, TDelegate>>(); private TDelegate _defaultAction; /// <summary> /// 构造一个空格中间件生成器 /// </summary> /// <param name="defaultAction">默认执行的动作。无论是否有注册中间件,都会默认执行,除非在某一个中间件中拒绝调用 next(context)。不能为 NULL</param> public SpaceMiddlewareBuilder(TDelegate defaultAction) { this._defaultAction = defaultAction ?? throw new ArgumentNullException(nameof(defaultAction)); } /// <summary> /// 使用中间件 /// </summary> /// <param name="middleware"></param> /// <returns></returns> public TChild Use(Func<TDelegate, TDelegate> middleware) { _middlewares.Add(middleware); return (TChild)this; } /// <summary> /// 生成 /// </summary> /// <returns></returns> public TDelegate Build() { _middlewares.Reverse(); TDelegate next = this._defaultAction; foreach (var middleware in _middlewares) { next = middleware(next); } return next; } /// <summary> /// 执行委托,返回附加的所有文本 /// </summary> /// <param name="builderAction"></param> /// <param name="delegateParam"></param> /// <returns></returns> public string Execute(Func<TChild, TChild> builderAction, TDelegateParam delegateParam) { if(builderAction == null) { return string.Empty; } TChild builder = new TChild(); builder = builderAction(builder); if (builder == null) { return string.Empty; } TDelegate tDelegate = builder.Build(); if(tDelegate == null) { return string.Empty; } tDelegate.DynamicInvoke(delegateParam); return delegateParam.GetAllText(); } } }
SpaceMiddlewareContext.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DesignSample { /// <summary> /// 空格中间件上下文 /// </summary> public class SpaceMiddlewareContext { private readonly StringBuilder _textBuilder; /// <summary> /// 构造函数 /// </summary> public SpaceMiddlewareContext() { _textBuilder = new StringBuilder(); } /// <summary> /// 增加一些文本字符串 /// </summary> /// <param name="text"></param> public void Add(string text) { if (_textBuilder.Length > 0) { _textBuilder.Append(" "); } _textBuilder.Append(text); } /// <summary> /// 获取到目前为止所有增加的文本字符串集合 /// </summary> /// <returns></returns> public string GetAllText() { return _textBuilder.ToString(); } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignSample { public class TrAttrTemplateContext : SpaceMiddlewareContext { public string TrAttrPrefix { get; set; } } public delegate void RequestDelegate(TrAttrTemplateContext arg); public class TrAttrTemplateBuilder : SpaceMiddlewareBuilder<RequestDelegate, TrAttrTemplateContext, TrAttrTemplateBuilder> { public TrAttrTemplateBuilder() : base(c => { c.Add($"{ c.TrAttrPrefix }-ending=\"true\""); }) { } } class Program { public static void Main(string[] args) { //PrintTrTag(null); //Test 1 //PrintTrTag(app => app); //Test 2 PrintTrTag(app => app.Use(AppendIdForTrTag) //给 tr 标签增加 ng-id 属性 .Use(AppendTimeForTrTag) //给 tr 标签增加 ng-time 属性 );//Test 3 } /* 假设本方法来自于你们公司的B部门,通过封装,用于给<tr>标签固定附加 ng-id 属性 */ static RequestDelegate AppendIdForTrTag(RequestDelegate next) => context => { context.Add($"{ context.TrAttrPrefix }-id=\"tr1\""); next(context); }; /* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */ static RequestDelegate AppendTimeForTrTag(RequestDelegate next) => context => { context.Add($"{ context.TrAttrPrefix }-time=\"{ DateTime.Now.ToString() }\""); next(context); }; /* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */ static void PrintTrTag(Func<TrAttrTemplateBuilder, TrAttrTemplateBuilder> trBuilderAction) { string htmlTempl = "<tr {0}></tr>"; string trAttrInner = new TrAttrTemplateBuilder().Execute(trBuilderAction, new TrAttrTemplateContext { TrAttrPrefix = "ng" }); string fullHtml = string.Format(htmlTempl, trAttrInner); Console.WriteLine(fullHtml); } } }
谢谢浏览!