优雅就一个字——设计模式之数据上传接口

在网上看到很多关于设计模式的文章。但是基本都是单独讲解某一个设计模式的应用场景和设计思路。可是真实的项目中,可能仅仅只按照书上的某种设计模式就能写出优雅的代码吗?我觉得是不可能的。我这篇文章希望跟大家分享的是我思考的过程,而非结果。首先,应该对书上的20多种的设计模式有了解,大概清楚它们都是怎么样一个设计思路。建议有想学习设计模式的Friends还是买本纸质书系统的学习。下面,我给出一个真实的项目来引出我对这个项目的思考。第一次写博客分享我的思路,在加上我的思维有些女性思维,是跳跃性的。可能有些表达不是很清楚。望大家见谅。

    • 看到这流程图,首先在我脑海里的就是这是由一个一个小方块组合起来的组合体。我们先不管具体代码该怎么写,类怎么设计。只知道这是一个组合体。会有很多类。说到组合,我们是否可以联想到这应该是一个结构型的设计。这个组合体是由这些小方块代表的类按照某种结构组合起来的。结构型的设计模式有哪些,大家脑海里应该会有个轮廓了。
    • 又看到每一个小方块有分支,2个分支,分别代表正确的时的下一个流程和不正确时的下一个流程。这是不是意味着,我的方法会一层一层往下调用,直到最后一个小方块对象的下个流程对象为null时停止。想到这,我脑海里想到了装饰者模式和职责链模式。可是装饰者模式没有判断条件,它只是按照你组合的顺序,依次往下调用。那么这是不是更加符合职责链模式呢?咋一看很像,职责链模式是在一个流程内,没有处理的权限就往后传递,有处理权限就跳出方法链。跟我们的2个分支有些不同。我们的需求是要既有权限处理往后传递,没有权限也要往后传递。想到这,我们就清楚了,在小方块所代表的类里,应当有两个属性,一个是判断条件为True时的下一流程对象,另一个是判断条件为False时下一流程对象。这样,小方块类的类结构里就有了两个属性了。
      1. 每个小方块都有两个属性,我们是否就应该有个规范呢?所以我们定义一个接口,让所有的小方块代表的类实现这个接口。接口里目前有两个属性。
    • 接着又想,每个小方块代表的类,所执行的具体业务逻辑不一样,所以,我们在接口里是否应该有个方法可供子类重写呢?这样一来,每个小方块所代表的类都有了自己的业务逻辑。但是,那在什么地方调用下个流程的业务逻辑呢?如果放在单独的每个小方块所代表的类中,那岂不是,我们在每一个小方块类中都要写一些重复的调用下个流程的代码呢?这样就不够优雅了。所以,我想要调用过程在父级类里实现。为了实现小方块类的多态和调用下个流程的代码复用,就有了一个能够有方法实现的类。这个类又必须包含抽象方法。那所有流程的抽象基类出来了。这个抽象类实现之前定义的接口。其实这个接口要不要都无所谓啦,不过好像每个设计模式都是从接口开始,那么就保留一个接口吧。
    • 抽象类有了,每个子类重写的业务逻辑方法也有了。接下来,就是写调用被重写的业务逻辑的方法了。此处,大家应该可以想到是一个模板方法吧。但是,我们这里有两个分支,具体调用哪一个分支是由当前的小方块类决定的。这样一想,那这个调用下个小方块类的业务逻辑方法的代码岂不是只能写在具体的每个小方块类里了。这样不是很麻烦吗?我们要想一个办法,将这个过程放在抽象类里解决。鉴于最多也就两个分支,不是正就是反。那么我们是否可以通过在抽象类里设置一个属性,来标识下一流程具体调用的是哪一个分支呢?所以我们抽象类里又有了一个属性。这个属性是要被子类在业务逻辑方法中重新赋值的。
      1. 在抽象类的调用下一流程的方法里,我们会有一个判断,判断这个属性所代表的下一流程具体是哪一个分支。
    • 当某些业务处理完之后,可能就直接要结束整个流程,比如说,如果我第一步验证没通过,那么后面的流程都不能被执行。所以,我们要能够随时退出整个流程。这样,我们跟上面决定调用哪个分支的设计思路一致,加一个属性,来标识说是否要结束整个流程。可供子类重新赋值。在父类的调用下一个流程的方法中做判断。
  • 那现在我们的抽象类里就有了3个属性,2个方法。
    1. 当条件判断为True时的下一流程属性
    2. 当条件判断为False时的下一流程属性
    3. 标识下一流程调用哪一个分支的属性
    4. 标识是否结束整个流程的属性
    5. 封装了调用过程的方法
    6. 需要被重写的的具体业务逻辑方法
  • 然后,总有参数要传递到每一个小方块类的业务逻辑方法中吧。那么我们这里就将所有参数封装成一个数据实体类。依次传递到每个小方块类的业务逻辑方法中。大概思路就说到这吧。还有一些业务需求没有讲到,那在代码里都有体现。先上代码吧。

 

    /// <summary>
    /// 处理流程基类
    /// </summary>
    public abstract class ProcessFlowBase : IProcessFlow
    {
        protected ProcessFlowBase(ProcessFlowBase processFlowWhenRight = default(ProcessFlowBase), ProcessFlowBase processFlowWhenWrong = default(ProcessFlowBase))
        {
            this.NextProcessFlowWhenRight = processFlowWhenRight;
            this.NextProcessFlowWhenWrong = processFlowWhenWrong;
            this.IsRight = true;
            this.IsEnd = false;
        }

        protected IDbConnection DbConnection { get; set; }

        protected IDbCommand DbCommand { get; set; }

        protected IDbTransaction DbTransaction { private get; set; }

        /// <summary>
        /// 当前流程是否处理通过
        /// </summary>
        private bool IsRight { get; set; }

        /// <summary>
        /// 流程是否结束
        /// </summary>
        private bool IsEnd { get; set; }

        /// <summary>
        /// 下一个流程,当流程处理操作通过的时候
        /// </summary>
        private ProcessFlowBase NextProcessFlowWhenRight { set; get; }

        /// <summary>
        /// 下一个流程,当流程处理操作不通过的时候
        /// </summary>
        private ProcessFlowBase NextProcessFlowWhenWrong { get; set; }

        /// <summary>
        /// 处理
        /// </summary>
        /// <param name="dataContext"></param>
        public void Process(DataContext dataContext)
        {
            this.ProcessTemplate(dataContext);
            this.RecordLog(dataContext);
            if (this.IsEnd) return;
            if (this.IsRight)
            {
                if (this.NextProcessFlowWhenRight == default(ProcessFlowBase)) return;
                this.NextProcessFlowWhenRight.SetParameters(this.DbConnection, this.DbCommand, this.DbTransaction);
                this.NextProcessFlowWhenRight.Process(dataContext);
            }
            else
            {
                if (this.NextProcessFlowWhenWrong == default(ProcessFlowBase)) return;
                this.NextProcessFlowWhenWrong.SetParameters(this.DbConnection, this.DbCommand, this.DbTransaction);
                this.NextProcessFlowWhenWrong.Process(dataContext);
            }
        }

        /// <summary>
        /// 流程处理模板方法,供子类实现
        /// </summary>
        /// <param name="dataContext"></param>
        protected abstract void ProcessTemplate(DataContext dataContext);

        /// <summary>
        /// 记录日志,供子类实现
        /// </summary>
        /// <param name="dataContext"></param>
        protected virtual void RecordLog(DataContext dataContext)
        {
            LogHelper.Record(dataContext);
        }

        /// <summary>
        /// 结束本次流程
        /// </summary>
        protected void EndProcessFlow()
        {
            this.IsEnd = true;
        }

        /// <summary>
        /// 确定下一流程,后续候选流程名单在调用构造函数的时候已经初始化好
        /// </summary>
        /// <param name="rightFlowOrWrongFlow"></param>
        protected void SetNextFlow(RightFlowOrWrongFlow rightFlowOrWrongFlow)
        {
            this.IsRight = rightFlowOrWrongFlow == RightFlowOrWrongFlow.Right;
        }

        /// <summary>
        /// 回滚操作流程
        /// </summary>
        protected void RollBackProcessFlow()
        {
            this.DbTransaction.Rollback();
            this.DbConnection.Close();
        }

        /// <summary>
        /// 提交事物操作
        /// </summary>
        protected void CommitProcessFlow()
        {
            this.DbTransaction.Commit();
            this.DbConnection.Close();
        }

        /// <summary>
        /// 设置下一流程单例属性
        /// </summary>
        /// <param name="param"></param>
        private void SetParameters(params object[] param)
        {
            var dbConnection = param[0] as IDbConnection;
            var dbCommand = param[1] as IDbCommand;
            var dbTransaction = param[2] as IDbTransaction;
            this.DbConnection = dbConnection;
            this.DbCommand = dbCommand;
            this.DbTransaction = dbTransaction;
        }
    }

 

 

    /// <summary>
    /// 检验授权码流程,此流程应当作为所有业务流程的入口流程。会在此类中做一些特别的处理
    /// </summary>
    public class CheckToken : ProcessFlowBase
    {
        public CheckToken(ProcessFlowBase processFlowWhenRight = default(ProcessFlowBase),
            ProcessFlowBase processFlowWhenWrong = default(ProcessFlowBase))
            : base(processFlowWhenRight, processFlowWhenWrong)
        {
            //这个流程作为所有业务处理的入口流程,所以,我在这里要写入一段初始化流程事务对象的代码,仅执行一次
            base.DbConnection = LogHelper.CreateDbConnection();
            base.DbConnection.Open();
            base.DbCommand = base.DbConnection.CreateCommand();
            base.DbTransaction = base.DbConnection.BeginTransaction();
        }

        protected override void ProcessTemplate(DataContext dataContext)
        {
            //查询授权码是否存在
            var sbSelectSql = new StringBuilder();
            sbSelectSql.AppendFormat(@"Some SQL Here", dataContext.AuthCode, dataContext.PartCode);
            dataContext.SQL = base.DbCommand.CommandText = sbSelectSql.ToString();
            var any = Convert.ToInt32(base.DbCommand.ExecuteScalar());
            if (any > 0)
            {
                base.SetNextFlow(RightFlowOrWrongFlow.Right);
            }
            else
            {
                dataContext.StatusCode = "1001";
                base.RollBackProcessFlow();
                base.EndProcessFlow();
            }
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="dataContext"></param>
        protected override void RecordLog(DataContext dataContext)
        {
        }
    }
 
    /// <summary>
    /// 读取包含数据的XML文件
    /// </summary>
    public class LoadXElement : ProcessFlowBase
    {
        public LoadXElement(ProcessFlowBase processFlowWhenRight = default(ProcessFlowBase), ProcessFlowBase processFlowWhenWrong = default(ProcessFlowBase))
            : base(processFlowWhenRight, processFlowWhenWrong) { }

        protected override void ProcessTemplate(DataContext dataContext)
        {
            try
            {
                using (var memoryStream = new MemoryStream(dataContext.Buffer))
                {
                    dataContext.DataXElement = XElement.Load(memoryStream);
                }
                var folderPath = HttpContext.Current.Server.MapPath("/ModuleSources/FileStore/AppFile/TunnelMeasure/Surface");
                if (!Directory.Exists(folderPath))
                    Directory.CreateDirectory(folderPath);
                var xmlPath =
                    string.Format(
                        folderPath + "/{0}_01_{1}.xml",
                        dataContext.PartCode, DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"));
                using (var fileStream = new FileStream(xmlPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                {
                    dataContext.DataXElement.Save(fileStream);
                }
                dataContext.XMLPath = xmlPath;
            }
            catch (Exception)
            {
                //读取文件流失败
                dataContext.StatusCode = "1002";
                base.RollBackProcessFlow();
                base.EndProcessFlow();
                return;
            }
            base.SetNextFlow(RightFlowOrWrongFlow.Right);
        }
    }
    
  • 最后想说的就是设计模式都是死的,就好像风云里无名的万剑归宗。当忘了所有的形式,无招胜有招。在上述的例子中,其实并没有严格完全按照书上的设计模式的范例。其中可能有模板方法、职责链、策略模式、状态模式等等啦。在中国合伙人中,孟晓骏说他们80后那一代人最重要的是改变。我觉得,我们90后这一代人最重要的是质疑。有太多的陋规和成见被一代一代传下来。我们要怀着质疑的心态去看世间万物。就好像曾经某届人人大代表说中国房价还不够高。当时觉得那人是24K纯StringBuilder可是当我读了《市场的力量》之后,想法有些许的改变了。有个例子。中国古代一发生天灾人祸时,就闹饥荒。百姓饿死的很多。有些黑心的商人就囤积居奇。朝廷为了稳定粮价,稳住民生。就严格调控粮价。结果是什么呢?结果是有更多的百姓饿死。因为那些商人看到朝廷如此打压粮价。索性就不卖了。他们也许知道这是刚性需求。百姓不得不妥协。那如果,朝廷不出面干预,就会有人看到商机,从外面运进粮食出售,从一定程度上缓解了粮食危机。这时的中国政府就是个反面例子。那还有一个例子就是二战后的德国,民不聊生,人民连维持基本生命需求的食物都不能满足。结果导致黑市横行。政府怎么管都无法消灭黑市。这时一个聪明的办法出来了。美国政府跟黑市一起搞。那市民还是觉得政府会更可靠吧。黑市逐渐的也就消亡了。美国的政治智慧还是很伟大的。核心思想就是妥协,也就是保持平衡。折射到中国房地产,也许先进的中国房价还不够高。政府如何调控,房价都不会有明显的下降。即便是房价下来了,那商人们会不会在其他地方增加隐形收费来弥补房价下跌的这个缺口呢?我想会的。也许中国房价在高些,高得大部分人买不起了。市场机制就展现出他的力量了。市场倒逼价格下降,服务优化。还是多看历史吧。也许我的见解也很片面。

posted @ 2014-04-09 11:33  Sago  阅读(1961)  评论(4编辑  收藏  举报