“硬核”代码重构

“硬核”代码重构

首页冒险解谜代码重构更新时间:2024-05-07

周末拍的梅花嘞

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

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

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

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

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

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

// 下面变量是和界面绑定的变量,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行代码 。

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

这就是我在写代码的时候一个小小的重构思路,希望能够帮助到大家一点 ,如果有帮助到, 我就很开心啦!!!

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved