面向对象编程实践--MapReduce模式

关键字: MapReduce模式, 关注点分离

MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。概念"Map(映射)"和"Reduce(归约)",是它们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。

上面是一般认识的MapReduce, 主要应用于大数据领域. 但是MapReduce的思想,在我们的日常编程中也是有很大的应用, 特别是利用LINQ所带来的处理方式改变,可以写出容易理解的代码.
我们日常处理的代码很多时候都是对一个集合进行处理,转化(MAP),聚合(Reduce)来获得最后的结果.
当然我们可以利用if/foreach来达到同样的效果, 但是太多的if/foreach 混合的计算机基础逻辑和业务逻辑, 很难做到关注点分离. 使用MapReduce后,可以让顶层代码,更加面向需求方, 可以用自然语言和客户解释逻辑,确认逻辑.

需求:####

我们有一个规则记录节, 里面每条规则有一个源表(及字段ID)和一个目标表(及字段ID). 现在需要把所有规则按照源表生成一个分组结构返回前端处理.

代码初稿:####

            var sections = _DbContext.StudyStandardMappingSection
                .Where(p => p.MappingID == mappingID && p.DataStatus != DataStatus.删除);

            var ret = Mapper.Map>(sections);

            foreach (var section in ret)
            {
                section.Tables = new List();

                //找出该分组下的规则
                var rules = _DbContext.StudyStandardMappingRule
                    .Where(p => p.MappingSectionID == section.MappingSectionID && p.DataStatus != DataStatus.删除);

                var ruleViewModels = Mapper.Map>(rules);

                if (rules != null)
                {
                    //将规则按表分类
                    var tables = ruleViewModels.ToLookup(s => new { s.SourceTableID, s.SourceFieldName });

                    foreach (var table in tables)
                    {
                        StudyStandardMappingTableViewModel tmp = new StudyStandardMappingTableViewModel();
                        tmp.SourceTableID = table.Key.SourceTableID;
                        tmp.SourceTableName = table.Key.SourceFieldName;
                        tmp.Rules = new List();

                        foreach (var rule in table)
                        {
                            tmp.SourceTableName = rule.SourceTableName;//(此处设置表名不好,待改进)

                            //将多选变量分类
                            var options = table.ToLookup(s => s.ParentID);

                            foreach (var option in options)
                            {
                                //判断是否为多选变量规则,若是0代表不是多选变量规则
                                if (option.Key == 0)
                                {
                                    tmp.Rules.Add(rule);
                                }
                                else
                                {//将选项值规则加入对应的多选变量规则中
                                    var optionRule = ruleViewModels.Where(s => s.MappingRuleID == option.Key).FirstOrDefault();
                                    optionRule.OptionValues = new List();

                                    foreach (var item in option)
                                    {
                                        optionRule.OptionValues.Add(item);
                                    }
                                }
                            }
                        }
                        section.Tables.Add(tmp);
                    }
                }
            }

应用MapReduce模式后代码:####


            var sections = _DbContext.StudyStandardMappingSection
                                        .Include("Rules")//取出子规则
                                        .Where(p => p.MappingID == mappingID)//只要某个映射下的所有节
                                        .ExcludeDeleteData()//排除删除的节
                                        .ToList()//排除数据库的影响,转化为list,以便后续处理
                                        .Select(p => RenderOneSectionViewModel(p, p.Rules));//构建一个分组节


        private StudyStandardMappingSectionViewModel RenderOneSectionViewModel(StudyStandardMappingSection section, IEnumerable rules)
        {
            var ret = Mapper.Map(section);

            ret.Tables = rules.ExcludeDeleteData()//排除删除的规则
                                .GroupBy(p => new { p.SourceTableID, p.SourceTableName })//按照源表ID和表名分组
                                .Select(p => CreateOneMappingTableViewModel(p.Key.SourceTableID, p.Key.SourceTableName, p))//按照表名,表ID依次为每张表构建ViewModel
                                .ToList();
            return ret;
        }

        private StudyStandardMappingTableViewModel CreateOneMappingTableViewModel(string sourceTableID, string sourceTableName, IEnumerable rules)
        {
            return new StudyStandardMappingTableViewModel
            {
                SourceTableID = sourceTableID,     //更新表ID
                SourceTableName = sourceTableName, //更新表名
                Rules = rules
                            .ExcludeDeleteData()   //排除已删除的规则
                            .UpdateRuleChildOption() //更新规则的选项值列表
                            .Where(p => p.ParentID <= 0)   //选择非选项的规则                            
                            .Select(p => Mapper.Map(p)) //转化为ViewModel
                            .ToList(),
            };
        }

        public static IEnumerable UpdateRuleChildOption(this IEnumerable rules)
        {
            return rules.Select(p => p.UpdateOptions(rules.Where(p => p.ParentID == mappingRuleID)));
        }

点评:

哪一种方法更好了? 直接看,初稿代码似乎更好,每个逻辑判断都直接在代码里面,似乎很清楚. 但是,每次看代码的时候, 都要不停的混合代码逻辑(if,else,foreach)和业务逻辑(如何构造表分组).每次看懂这个代码都要10几分钟.
第二种方法,基本上都是业务的语言来构建逻辑, 不用一分钟就知道代码在干什么,很容易发现业务逻辑是否有问题, 也容易跟随业务变化而变化. 但是底层算法都被保证在外部代码或者小函数里面, 调试起来还是挺麻烦的. 当然,这里还有一个非常大的好处,就是代码复用, 原来的代码很难复用,导致在几个地方重复,改造后,只需要调用相关逻辑算法就好.

你可能感兴趣的:(面向对象编程实践--MapReduce模式)