设计模式-责任链模式引发的思考
背景:
在业务频繁迭代的时候,有时候一个菜单页面对应的后台代码会越来越凌乱,一个方法本来就做A、B事情,后面迭代,变成会做A、B、C、D、E事情,且A、B又细分出a1、a2、a3、a4、b1、b2、b3。一个菜单页开始设计代码时,通常写法都较为面向对象,后面经多个人,可能是不同的人迭代后就越来越面向流程。
为什么后面越来越面向流程呢?大约是因为方便吧。如果只是迭代一个小逻辑,一旦要抽出一些通用性的东西,面向对象,写出好扩展的代码,要考虑的情况可能涉及:之前的业务,牵涉到的上下文变量,跟UI的交互(例如弹窗提示报错,询问用户是否继续某操作等等),把之前上线过的东西抽出来放到其他地方又增加了测试的地方等等,太难了。
但代码还能能简单改造一下,这种业务流程像是可以通过责任链设计模式来重构代码。但是这种模式有点隆重感,建好多类,又要抽象类,好像把一个菜单的后台代码复杂化了。但是它的本质,职责层层传递确实又让扩展容易,阅读代码容易。
代码重构过程:
重构前:
private void buttonOld_Click(object sender, EventArgs e) { string fundId = "2323112"; string fundCode = ""; //跨a3、b1使用 string poolID = "";//跨a1、a2使用 string fundName = ""; //A业务 //a1验证 //... poolID = "787908AA"; //... //a2验证 int count = 0; //... if (count == 0) { MessageBox.Show($"{fundId}不在配置数据里;"); LogHelper("...."); return; } //a3验证 //.... if (poolID == "33333") { //... } fundName = "新能源混合"; fundCode = "908898"; //... //B业务 //b1验证 List<string> list = new List<string>(); if (list.Contains(fundCode)) { //... if (MessageBox.Show($"{fundName}确认发送给某某用户", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } } }
重构后:
using System; using System.Collections.Generic; using System.Data; using System.Windows.Forms; namespace WindowsFormsApp2 { public partial class Form1 : Form { private DataTable ConfigTable; private Dictionary<string, string> LimitDict; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { ConfigTable = new DataTable(); //... LimitDict = new Dictionary<string, string>(); //... } private void buttonNew_Click(object sender, EventArgs e) { string checkErrMesg = ""; string fundID = "2323112"; string fundCode; string fundName; //... CheckBXFund checkBXFund = new CheckBXFund(LogHelper,ConfigTable, LimitDict); if(checkBXFund.Handle(fundID,ref checkErrMesg) == false) { MessageBox.Show(checkErrMesg); return; } fundCode = checkBXFund.OutFundCode; fundName = checkBXFund.OutFundName; //... CheckRisk checkRisk = new CheckRisk(); // if(checkRisk.Handle(fundCode, ref checkErrMesg)==false) { MessageBox.Show(checkErrMesg); return; } //... } private void LogHelper(string Message) { } } /// <summary> /// 假设是整个A业务 /// </summary> internal class CheckBXFund { //应当返回出去的值 1、基金名称 2 基金代码 public string OutFundName; public string OutFundCode; //外面传进来协助验证的一些变量 private DataTable InConfigTable; private Dictionary<string, string> InRepeatDict; private Action<string> LogAction; //有一些操作可能要用外面的窗体实例,例如只有窗体可以Log:this.Log() //方法之间传递的变量,方便跨方法调用 private string PoolID; //参数变量,不必重复获取的一些变量 public CheckBXFund(Action<string> logAction, DataTable dt, Dictionary<string, string> dict) { InConfigTable = dt; InRepeatDict = dict; LogAction = logAction; } public bool Handle(string fundId, ref string errorMessage) { if(IsRepeat(fundId,ref errorMessage) == false) { return false; } if (IsInConfig(fundId, ref errorMessage) == false) { return false; } if (IsCanGetName(fundId, ref errorMessage) == false) { return false; } return true; } /// <summary> /// 假设是a1步骤 /// </summary> /// <param name="fundId"></param> /// <param name="errorMessage"></param> /// <returns></returns> private bool IsRepeat(string fundId,ref string errorMessage) { //... PoolID = "787908AA"; //... return false; } /// <summary> /// 假设是a2步骤 /// </summary> /// <param name="fundId"></param> /// <param name="errorMessage"></param> /// <returns></returns> private bool IsInConfig(string fundId,ref string errorMessage) { int count = 0; //... if (count == 0) { errorMessage = $"{fundId}不在配置数据里;"; LogAction("...."); return false; } return true; } /// <summary> /// 假设是a3步骤 /// </summary> /// <param name="fundId"></param> /// <param name="errMessage"></param> /// <returns></returns> private bool IsCanGetName(string fundId,ref string errMessage) { //.... if (PoolID == "33333") { //... } OutFundName = "新能源混合"; OutFundCode = "908898"; return true; } } /// <summary> /// 假设是整个B业务 /// </summary> internal class CheckRisk { //... public bool Handle(string fundCode,ref string errMessage) { //... return true; } //... } }
总结:在一个类中封装一个业务,职责传递通过一个Handle方法组装,每一个职责就一个方法。跨大业务(大A大B)小业务(小a1、小a2等)的传值通过公共变量传递,和UI的交互通过委托,或者只有窗体实例才能调的方法也通过委托。这一整个类属于菜单的后台代码业务帮助类,和菜单粘性较强。
量变会引起质变。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· ASP.NET Core - 日志记录系统(二)
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入
· .NET 开发的分流抢票软件,不做广告、不收集隐私
· ASP.NET Core - 日志记录系统(二)
· C#实现 Winform 程序在系统托盘显示图标 & 开机自启动
· 实现windows下简单的自动化窗口管理
2018-07-02 Windows下vue-cli脚手架搭建入门<一>
2018-07-02 Windows安装diango框架<一>