设计模式-责任链模式引发的思考

背景:

在业务频繁迭代的时候,有时候一个菜单页面对应的后台代码会越来越凌乱,一个方法本来就做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;
                }
            }
        }
View Code

重构后:

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;
        }
        //...
    }
}
View Code

总结:在一个类中封装一个业务,职责传递通过一个Handle方法组装,每一个职责就一个方法。跨大业务(大A大B)小业务(小a1、小a2等)的传值通过公共变量传递,和UI的交互通过委托,或者只有窗体实例才能调的方法也通过委托。这一整个类属于菜单的后台代码业务帮助类,和菜单粘性较强。

量变会引起质变。
原文地址:https://www.cnblogs.com/bibi-feiniaoyuan/p/14959967.html