关于审批成功或确认逆向操作下有多个相同动作的程序设计

我们在开发过程中,一般都会遇到这样的需求吧。
审批通过的时候要执行多个动作:

1.更改A表的状态为“已审批”,我们记为操作A

2.插入B表一条数据 ,我们记为操作B

3.更改C表的多条数据的状态,我们记为操作C

N多

.......

但是当N多天后,在业务发生需要逆向这个审批的时候,我们需要回滚这些操作。

我们需要一个不漏的逆向刚刚审批做的操作。

这个时候如果我们这样写:

审批方法()

{

1.动作A

2.动作B

3.动作C

......

}

逆向方法()

{

1.逆向A

2.逆向B

3.逆向C

......

}

这样的话,如果后续业务再增加一个动作的时候,需要改动两处地方,万一漏掉一处(往往都是逆向处) ,并且测试都没测出来,那么问题就可大可小了。

我们从程序设计上就可以避免这个问题的产生。

我这边是生成付款清单*(情形类似)为例:

1.先定义一个接口,包含两个方法:生成与删除

    public interface IPayToDealerOperate
    {
        /// <summary>
        /// 生成付款明细接口
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbQuery"></param>
        /// <param name="listWarranty"></param>
        /// <param name="currentId"></param>
        /// <returns></returns>
        List<ClmPayToDealer> GeneratePayDetail(CEPEntities db, CepOneViewEntities dbQuery, List<ClmWarranty> listWarranty, long currentId);
        /// <summary>
        /// 删除付款明细接口
        /// </summary>
        /// <param name="DbContext"></param>
        /// <param name="dbQuery"></param>
        /// <param name="payMasterId"></param>
        /// <param name="currentId"></param>
        /// <param name="payDetailId"></param>
        /// <returns></returns>
        string DeletePayDetail(CEPEntities DbContext, List<ClmPayToDealer> payItemAllList, ClmPayToDealer pDetail, long currentId);
    }

2.为每个子动作分别创建类,并分别实现上面接口

    public class PayNormalDetailImpl : IPayToDealerOperate
    {
        /// <summary>
        /// 生成付款明细接口
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbQuery"></param>
        /// <param name="listWarranty"></param>
        /// <param name="currentId"></param>
        /// <returns></returns>
        public List<ClmPayToDealer> GeneratePayDetail(CEPEntities db, CepOneViewEntities dbQuery, List<ClmWarranty> listWarranty, long currentId)
        {
             //内含正常保修单生成付款项操作,此动作非重点已省略

            return listPayToDealer;
        }
        /// <summary>
        /// 删除付款明细接口
        /// </summary>
        /// <param name="DbContext"></param>
        /// <param name="dbQuery"></param>
        /// <param name="payMasterId"></param>
        /// <param name="currentId"></param>
        /// <param name="payDetailId"></param>
        /// <returns></returns>
        public string DeletePayDetail(CEPEntities DbContext, List<ClmPayToDealer> payItemAllList, ClmPayToDealer pDetail, long currentId)
        {
             //内含收货入库删除操作,此动作非重点已省略

            return string.Empty;
        }
    }
    public class PayPartReceiveInstockDetailImpl : IPayToDealerOperate
    {
        /// <summary>
        /// 生成付款明细接口
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbQuery"></param>
        /// <param name="listWarranty"></param>
        /// <param name="currentId"></param>
        /// <returns></returns>
        public List<ClmPayToDealer> GeneratePayDetail(CEPEntities db, CepOneViewEntities dbQuery, List<ClmWarranty> listWarranty, long currentId)
        {
             //内含审计扣款生成付款项操作,此动作非重点已省略

            return listPayToDealer;

            
        }
        /// <summary>
        /// 删除付款明细接口
        /// </summary>
        /// <param name="DbContext"></param>
        /// <param name="dbQuery"></param>
        /// <param name="payMasterId"></param>
        /// <param name="currentId"></param>
        /// <param name="payDetailId"></param>
        /// <returns></returns>
        public string DeletePayDetail(CEPEntities DbContext, List<ClmPayToDealer> payItemAllList, ClmPayToDealer pDetail, long currentId)
        {
            //内含收货入库删除操作,此动作非重点已省略

            return string.Empty;

        }
    }
    public class PayAuditDebitImpl : IPayToDealerOperate
    {
        /// <summary>
        /// 生成付款明细接口
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbQuery"></param>
        /// <param name="listWarranty"></param>
        /// <param name="currentId"></param>
        /// <returns></returns>
        public List<ClmPayToDealer> GeneratePayDetail(CEPEntities db, CepOneViewEntities dbQuery, List<ClmWarranty> listWarranty, long currentId)
        {
            //内含审计扣款生成付款项操作,此动作非重点已省略

            return listPayToDealer;
        }
        /// <summary>
        /// 删除付款明细接口
        /// </summary>
        /// <param name="DbContext"></param>
        /// <param name="dbQuery"></param>
        /// <param name="payMasterId"></param>
        /// <param name="currentId"></param>
        /// <param name="payDetailId"></param>
        /// <returns></returns>
        public string DeletePayDetail(CEPEntities DbContext, List<ClmPayToDealer> payItemAllList, ClmPayToDealer pDetail, long currentId)
        {
            //内含审计删除操作,此动作非重点已省略

            return string.Empty;

        }
    }

3.在调用处定义接口数组:

        /// <summary>
        /// 付款清单新增数据与删除数据,统一管理入口
        /// </summary>
        private IPayToDealerOperate[] _payDetailOperateArray = new IPayToDealerOperate[] {
            new PayNormalDetailImpl(),//正常付款清单
            new PayPartReceiveInstockDetailImpl(),//零件收货入库扣款
            new PayAuditDebitImpl()//保修审计扣款
        };

4.在调用处循环数组执行相应动作。

4.1 在生成付款单处执行生成动作。

                        foreach (var action in _payDetailOperateArray)
                        {
                            listPayTotalItem.AddRange(action.GeneratePayDetail(db, dbQuery, item.ToList(), currentId));
                        }

4.2 在删除付款单时执行删除动作。

               //循环处理_payDetailOperateArray中包含的还原扣款信息
                foreach (var action in _payDetailOperateArray)
                {
                    action.DeletePayDetail(DbContext, payItemAllList, pdForDel, currentId);
                }

至此,大功告成。如若后续业务需要增加扣款项,那么我只需新建一个类,这个类实现了最初定义的接口,那么我就必须去实现生成和退回操作,从而避免了漏操作的尴尬,同时也遵循着开闭原则。

补充,如果我增加了一个业务,只需要在生成付款项的时候进行动作,删除的时候不要有动作,那么只要实现这个删除动作,直接返回即可。

原文地址:https://www.cnblogs.com/zhanghai/p/9856073.html