“硬核”代码重构

在学习编程的路上,相信大家这几个词一定不少听,什么 面相对象、封装继承多态、内功心法21种设计模式 等等 。但是却很少用到,或者说用到的都是被动使用。大牛们在写代码前早就构思好了,接口,基类等等。自己写代码的时候,很少有把面向对象想的面很全,很容易在遇上不够优秀的代码,这时候就需要重构了。

但是我们却很少去重构,可能原因有很多,比如很重要的一点:不想改出Bug;不想增加工作量(我是要5点半下班的男人,女朋友还在等我做饭);时间很紧,先实现功能先;代码是82年的不敢动!!!

其实重构可以写出更健壮的代码、减少后面的工作量、让开发者更好阅读。看了很多重构的文章,发现很多是一些基本的,命名规范或者拆函数什么的。这篇文章写下我重构的一些思路和重构之前代码对比。好了,废话不多说,上项目。威武、威武、威武........

简单介绍一下项目,项目就是一个客户端小工具用来审核编写递交的说明是否规范。这里说下,面向对象是一种思想,和语言无关。只要是面向对象语言,无论你是C#、Java、TypeScript、Python,都是可以用这种思想重构的。

tools.png

上图就是小工具了一个部分截图,有若干个栏,每个栏都是填写一些对应的修改内容,在审核校验时,会检查写的内容是否符合标准。

前辈已经完成一些栏的校验,我的任务是完成剩下栏:写正则表达式,然后在不标准的时候提示就好了,是不是觉得根本没有必要重构,依葫芦画瓢就好了?在我拿到代码的时候,是这样的代码:

// 下面变量是和界面绑定的变量,RaisePropertyChanged作用在变量改变的时候通知前端重新渲染
// 不熟悉C#代码的,只用知道这些变量就是和前台绑定的就是了

        private string _editDescription;
        /// <summary>
        /// 修改说明内容
        /// </summary>
        public string EditDescription
        {
            get { return _editDescription; }
            set
            {
                _editDescription = value;
                RaisePropertyChanged(() => EditDescription);
            }
        }

        private string _editDescriptionRules;
        /// <summary>
        /// 修改说明校验规则
        /// </summary>
        public string EditDescriptionRules
        {
            get { return _editDescriptionRules; }
            set
            {
                _editDescriptionRules = value;
                RaisePropertyChanged(() => EditDescriptionRules);
            }
        }

        private bool _editDescriptionHasValidationError;
        /// <summary>
        /// 修改说明校验标志
        /// </summary>
        public bool EditDescriptionHasValidationError
        {
            get { return _editDescriptionHasValidationError; }
            set
            {
                _editDescriptionHasValidationError = value;
                RaisePropertyChanged(() => EditDescriptionHasValidationError);
            }
        }

        private string _integratedNote;
        /// <summary>
        /// 集成注意内容
        /// </summary>
        public string IntegratedNote
        {
            get { return _integratedNote; }
            set
            {
                _integratedNote = value;
                RaisePropertyChanged(() => IntegratedNote);
            }
        }

        private string _integratedNoteRules;
        /// <summary>
        /// 集成注意规则
        /// </summary>
        public string IntegratedNoteRules
        {
            get { return _integratedNoteRules; }
            set
            {
                _integratedNoteRules = value;
                RaisePropertyChanged(() => IntegratedNoteRules);
            }
        }

        private bool _integratedNoteHasValidationError;
        /// <summary>
        /// 集成注意校验标志
        /// </summary>
        public bool IntegratedNoteHasValidationError
        {
            get { return _integratedNoteHasValidationError; }
            set
            {
                _integratedNoteHasValidationError = value;
                RaisePropertyChanged(() => IntegratedNoteHasValidationError);
            }
        }
        
    // 这里随便举了两栏的变量,后面还有若干栏。

依葫芦画瓢以后呢,我发现原来是这样的。每一栏用了单独三个变量直接去绑定:编写的内容、是否标准的标志、不标准提示语。我是一个懒人啊,在我画了两个瓢以后,就很烦(一直在那复制变量,在那改来改去),这些个变量都是差不多一个意思。为啥让我重复在复制,修改呢?

明显每栏有相同项啊,对不对,一个是内容,一个状态,一个是错误提示语啊,咆哮!!!

这时候,我想起了书本上的一句话: "早重构,常重构"

我已经安奈不住我那颗懒惰的心里,因为下面还有“狠多狠多”栏,每一行有三个类似的变量,我这依葫芦画瓢,这个星期加班,就在复制粘贴去了。我是要上进,要每天进步的人,不能这样!

我为啥不能将这相同的共性抽象出来呢?是不咯,这个时候,我想起了《葵花宝典》的第一页的第一句:“万物皆对象”,于是本能的告诉我,每一栏看做一个对象,只是每栏的值不一样。然后我就写了一个”鸡肋“(基类),代码如下:

    /// <summary>
    /// 栏 基类
    /// </summary>
    public class Base: ObservableObject
    {
        private string _content;
        /// <summary>
        /// 内容
        /// </summary>
        public virtual string Content
        {
            get { return _content; }
            set
            {
                _content = value;
                RaisePropertyChanged(() => Content);
            }
        }

        private string _errorTip;
        /// <summary>
        /// 错误提示
        /// </summary>
        public virtual string ErrorTip
        {
            get { return _errorTip; }
            set
            {
                _errorTip = value;
                RaisePropertyChanged(() => ErrorTip);
            }
        }

        private bool _isError;
        /// <summary>
        /// 是否错误
        /// </summary>
        public virtual bool IsError
        {
            get { return _isError; }
            set
            {
                _isError = value;
                RaisePropertyChanged(() => ErrorTip);
            }
        }
    }

virtual是为了让子类能够重写get和set(如果有需求的话,为后面扩展做准备),然后字段从3个变到了1个了。

        /// <summary>
        /// 修改说明栏
        /// </summary>
        public class EditDescription : Base { }     

        private EditDescription _editDescriptions;
        /// <summary>
        /// 修改说栏绑定变量
        /// </summary>
        public EditDescription EditDescriptions
        {
            get { return _editDescriptions; }
            set
            {
                _editDescriptions = value;
                RaisePropertyChanged(() => EditDescriptions);
            }
        }
        
        // 其他的一样,我就不多写了

那,我们来算一下账,原先的变量,每一栏有3个变量,一个变量有6行代码的话,我这个有100栏,就是:

重构前: 100(栏)x3x6 = 1800 行代码 (阿西吧!!!)。
重构后: 100(栏)x1x6 = 600 行代码 。
小学算数: 1800 - 600 = 1200 (1200行,你说干点啥不好啊)

秀儿们算下,你花这么多时间,在那复制粘贴,不敢去动前辈们的代码,还是勇敢一点呢?

然后是不是感觉到一个继承就简单了很多呢,这只是一个面向对象的简单运用,就让我们少写了这么多代码。

前辈和我说,写代码就像练武功,就像你会了“九阳神功”或者"吸星大法",学其他武功看一眼就会。也就是说,当你理解了面向对象以后呢,你自然而然的就会写出很精简的代码了。阿西吧,又扯远了。

变量好了,抬头一看函数,我的脸便有点抽搐,啊!!这函数有毒!函数是这样的:

        // 此处函数用来设置每一栏报错时边框变红
        private void SetValidateFlag()
        {
            // 绑定的实体类判断状态
            if (tsEntity.EditDescriptionHasValidationError)
            {
                // 控件边框改颜色
                EditDescriptionHsExpander.BorderThickness = new Thickness(1);
                EditDescriptionHsExpander.BorderBrush = _readBrush;
            }

            if (tsEntity.TestSuggestionHasValidationError)
            {
                TestSuggestionHsExpander.BorderThickness = new Thickness(1);
                TestSuggestionHsExpander.BorderBrush = _readBrush;
            }

            if (tsEntity.IntegratedNoteHasValidationError)
            {
                IntegratedNoteHsExpander.BorderThickness = new Thickness(1);
                IntegratedNoteHsExpander.BorderBrush = _readBrush;
            }
            // 此处省略若干if,每个栏都有一个if
        }

然后大家懂的嘛,在我改了两栏以后,我又耐不住性子了。再一看,感觉似曾相识燕归来的感觉啊!有没有,每个if中都有三个类似的东西。我那个心啊,又忍不住悸动了起来,像是等初恋的感觉,想她来,来了又不知道要干哈。然后我发现其实if中判断的就是每栏的状态,括号里面是对控件栏的设置。然后想嘛,能不能搞个类似循环的东西,只要写一个for就好了呢。

思考以后,是这样的,我把控件也变成了栏的一个属性了,这样if判断里面就都是判断一个类了。代码就变成了这样:

    public class Base: ObservableObject
    {
        /// <summary>
        /// 模块控件(新增)
        /// </summary>
        public object Control { get; set; }
        
        //其他的和上面的Base一样
    }

然后 SetValidateFlag() 函数就变成了这样:

        /// <summary>
        /// 设置校验界面效果
        /// </summary>
        private void SetValidateFlag()
        {
            // listBase 所有栏实体集合
            foreach (var item in listBase)
            {
                if (item.IsError)
                {
                    var control = item.Control as HsExpander;
                    if (control == null)
                        continue;
                    // 将控件的边框变成红色
                    control.BorderThickness = new Thickness(1);
                    control.BorderBrush = _readBrush;
                }
            }
        }

好了嘞,好好的一个if的葫芦瓢给咱给整没了。这时候我们来算算我们这个重构,省了多少事。老样子:

原先的一个if算5行代码,我这个有100栏,就是:

重构前: 100(栏)x 5 = 500 行代码 (全是if啊)。
重构后: 我数了一下,没有错的话应该是:14行代码 。
小学算: 500 - 14 = 486

重构一下以后,感觉一颗心得到了小小满足。感觉灵魂得到了升华,不知道是自己太容易满足,还是代码世界里给我的成就感。感觉“乾坤大挪移”瞬间上了两层。

这就是我在写代码的时候一个小小的重构思路,希望能够帮助到大家一点。然后这个是我的Github,如果有帮助到大家的项目,可以给我点个star, 小生在这边谢谢啦!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,678评论 1 45
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,138评论 1 32
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,808评论 0 10
  • 可能就是怕自己做了错事,也希望对方能够理解。然后再也不要说出来。 但是,我只是从你口中听出:能不能不要再提那件事了...
    贤二_a6b3阅读 269评论 0 0
  • 麻省的春季总是如此悄无声息 漫长的冬季 厚重的积雪 温柔的暖光 龟缩的生命 如同从冰冻中冲进和煦 脸颊上的冰寸寸 ...
    六十七六阅读 250评论 0 1