面向对象编程实践--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<IEnumerable<StudyStandardMappingSectionViewModel>>(sections);

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

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

                var ruleViewModels = Mapper.Map<IEnumerable<StudyStandardMappingRuleViewModel>>(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<StudyStandardMappingRuleViewModel>();

                        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<StudyStandardMappingRuleViewModel>();

                                    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<StudyStandardMappingRule> rules)
        {
            var ret = Mapper.Map<StudyStandardMappingSectionViewModel>(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<StudyStandardMappingRule> rules)
        {
            return new StudyStandardMappingTableViewModel
            {
                SourceTableID = sourceTableID,     //更新表ID
                SourceTableName = sourceTableName, //更新表名
                Rules = rules
                            .ExcludeDeleteData()   //排除已删除的规则
                            .UpdateRuleChildOption() //更新规则的选项值列表
                            .Where(p => p.ParentID <= 0)   //选择非选项的规则                            
                            .Select(p => Mapper.Map<StudyStandardMappingRuleViewModel>(p)) //转化为ViewModel
                            .ToList(),
            };
        }

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

点评:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容