链式调用 - 封装业务函数
用设计模式、AOP能将一个方法/函数包裹起来,并且插入额外的逻辑行为,不过动作比较大,不是很灵活,下面介绍一种链式调用方法来封装的代码,完成后能实现如下的链式调用:
public class BO { public bool Add(string msg) { Console.WriteLine("Add"); if (msg == null) throw new Exception(); return true; } } static void Main(string[] args) { BO bo=new BO(); Pipeline<string, bool> p = Pipeline.Wrap<string, bool>(bo.Add) .BeforeExecute(m=>Console.WriteLine("before execute")) .AfterExecute((m, n) => Console.WriteLine("after execute1")) .AfterExecute((m, n) => Console.WriteLine("after execute2")) .Success((m, n) => Console.WriteLine("success")) .Fail((m, n) => Console.WriteLine("fail")) .Final((m, n) => Console.WriteLine("final")); Console.WriteLine("Result: "+p.Execute("testing").Result); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Result: " + p.Execute(null).Result); Console.ReadKey(); }
运行图:
注意:这个封装会对目标业务函数加入try/catch来得到业务是否成功执行。
实现起来比较简单,就是每个函数返回自身,如下:
public static class Pipeline//这里只实现了2个泛型,可以增加很多个(这点比较麻烦) { public static Pipeline<TIN, TOUT> Wrap<TIN, TOUT>(Func<TIN, TOUT> method) { Pipeline<TIN, TOUT> p = new Pipeline<TIN, TOUT>(method); return p; } public static Pipeline<TIN1, TIN2, TOUT> Wrap<TIN1, TIN2, TOUT>(Func<TIN1, TIN2, TOUT> method) { Pipeline<TIN1, TIN2, TOUT> p = new Pipeline<TIN1, TIN2, TOUT>(method); return p; } }
最终返回的结果对象:
public struct PipelineResult<TOUT> { /// <summary> /// 目标核心函数返回值 /// </summary> public TOUT Result { get; set; } /// <summary> /// 是否存在异常 /// </summary> public bool ExceptionExists { get; set; } /// <summary> /// 具体的异常 /// </summary> public Exception Exception { get; set; } }
只有一个输入参数的Wrapper:
public class Pipeline<TIN, TOUT> { private Func<TIN, TOUT> method2Execute; private List<Action<TIN>> beforeExecuteActions = new List<Action<TIN>>(); private List<Action<TIN, TOUT>> afterExecuteActions = new List<Action<TIN, TOUT>>(); private Action<TIN, TOUT> finalAction; private List<Action<TIN, TOUT>> successActions = new List<Action<TIN, TOUT>>(); private List<Action<TIN, TOUT>> failActions = new List<Action<TIN, TOUT>>(); public Pipeline(Func<TIN, TOUT> method) { this.method2Execute = method; } public Pipeline<TIN, TOUT> BeforeExecute(Action<TIN> action) { beforeExecuteActions.Add(action); return this; } public Pipeline<TIN, TOUT> AfterExecute(Action<TIN, TOUT> action) { afterExecuteActions.Add(action); return this; } public Pipeline<TIN, TOUT> Final(Action<TIN, TOUT> action) { this.finalAction = action; return this; } public Pipeline<TIN, TOUT> Success(Action<TIN, TOUT> action) { successActions.Add(action); return this; } public Pipeline<TIN, TOUT> Fail(Action<TIN, TOUT> action) { failActions.Add(action); return this; } public PipelineResult<TOUT> Execute(TIN argument) { PipelineResult<TOUT> result = new PipelineResult<TOUT>(); foreach (var action in this.beforeExecuteActions) action.Invoke(argument); try { result.Result = this.method2Execute.Invoke(argument); result.ExceptionExists = false; result.Exception = null; } catch (Exception ex) { result.ExceptionExists = true; result.Exception = ex; } foreach (var action in this.afterExecuteActions) action.Invoke(argument, result.Result); if (!result.ExceptionExists) { foreach (var action in this.successActions) action.Invoke(argument, result.Result); } else { foreach (var action in this.failActions) action.Invoke(argument, result.Result); } if (this.finalAction != null) this.finalAction.Invoke(argument, result.Result); return result; } }
支持2个输入参数的Wrapper:
public class Pipeline<TIN1, TIN2, TOUT> { private Func<TIN1, TIN2, TOUT> method2Execute; private List<Action<TIN1, TIN2>> beforeExecuteActions = new List<Action<TIN1, TIN2>>(); private List<Action<TIN1, TIN2, TOUT>> afterExecuteActions = new List<Action<TIN1, TIN2, TOUT>>(); private Action<TIN1, TIN2, TOUT> finalAction; private List<Action<TIN1, TIN2, TOUT>> successActions = new List<Action<TIN1, TIN2, TOUT>>(); private List<Action<TIN1, TIN2, TOUT>> failActions = new List<Action<TIN1, TIN2, TOUT>>(); public Pipeline(Func<TIN1, TIN2, TOUT> method) { this.method2Execute = method; } public Pipeline<TIN1, TIN2, TOUT> BeforeExecute(Action<TIN1, TIN2> action) { beforeExecuteActions.Add(action); return this; } public Pipeline<TIN1, TIN2, TOUT> AfterExecute(Action<TIN1, TIN2, TOUT> action) { afterExecuteActions.Add(action); return this; } public Pipeline<TIN1, TIN2, TOUT> Final(Action<TIN1, TIN2, TOUT> action) { this.finalAction = action; return this; } public Pipeline<TIN1, TIN2, TOUT> Success(Action<TIN1, TIN2, TOUT> action) { successActions.Add(action); return this; } public Pipeline<TIN1, TIN2, TOUT> Fail(Action<TIN1, TIN2, TOUT> action) { failActions.Add(action); return this; } public PipelineResult<TOUT> Execute(TIN1 argument1, TIN2 argument2) { PipelineResult<TOUT> result = new PipelineResult<TOUT>(); foreach (var action in this.beforeExecuteActions) action.Invoke(argument1, argument2); try { result.Result = this.method2Execute.Invoke(argument1, argument2); result.ExceptionExists = false; result.Exception = null; } catch (Exception ex) { result.ExceptionExists = true; result.Exception = ex; } foreach (var action in this.afterExecuteActions) action.Invoke(argument1, argument2, result.Result); if (!result.ExceptionExists) { foreach (var action in this.successActions) action.Invoke(argument1, argument2, result.Result); } else { foreach (var action in this.failActions) action.Invoke(argument1, argument2, result.Result); } if (this.finalAction != null) this.finalAction.Invoke(argument1, argument2, result.Result); return result; } }
支持更多输入参数的?不要返回值的?自己搞定吧。
尽管这个模式很简单,但是只要扩展一下,就能做简单的复合业务逻辑,比如xml文件来配置,最终组合成复合业务,很有潜力的一个模式。
自省推动进步,视野决定未来。
心怀远大理想。
为了家庭幸福而努力。
商业合作请看此处:https://www.magicube.ai
心怀远大理想。
为了家庭幸福而努力。
商业合作请看此处:https://www.magicube.ai