“硬核”代码重构

在学习编程的路上,相信大家这几个词一定不少听,什么 面相对象、封装继承多态、内功心法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行代码 。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上传jar包到nexus私服

进入maven管理页面&#xff0c;登录管理员账号 完成后可以进入对应目录下查看pom依赖 通过maven的方式depoly 在maven的conf/setting.xml 配置nexus私服的管理账号 在servers标签下添加server <server><id>nexus-snapshots</id><username>repouser<…

手把手教你写高质量Android技术博客,画图工具,录像工具,Markdown写法

前言 作为程序员&#xff0c;写博客是一件很有意义的事情&#xff0c;可以加深自己对技术的理解&#xff0c;可以结交更多的朋友&#xff0c;记录自己的技术轨迹&#xff0c;而且分享可以让更多的人从中受益&#xff0c;独乐乐不如众乐乐嘛。 但是要写好博客也不是件容易的事&a…

【Android】RxJava的使用(四)线程控制 —— Scheduler

前言 经过前几篇的介绍&#xff0c;对RxJava对模式有了一定的理解&#xff1a;由Observable发起事件&#xff0c;经过中间的处理后由Observer消费。&#xff08;对RxJava还不了解的可以出门左拐&#xff09;之前的代码中&#xff0c;事件的发起和消费都是在同一个线程中执行&am…

sed: -e expression #1, unknown option to `s'解决办法

报错如下&#xff1a; sed: -e expression #1, char 13: unknown option to s 需要替换的行为&#xff1a; monitor.urlhttp://192.168.25.100:8443/rest 查询资料得知&#xff0c;报错是因为替换的字符串包含有分隔符/ 所以这行改一下分隔符就可以解决问题了 改成感叹号!或者|…

Linux常用开发环境软件-Redis安装(docker环境下)

linux&#xff0c;docker安装RabbitMQ版本 1、从docker官网仓库下载安装RabbitMQ镜像 官网地址&#xff1a;https://hub.docker.com/ docker pull redis:4.0.8  //后面是版本,Tag Name 2、启动Docker Redis镜像 docker run -d -p 6379:6379 redis:4.0.8  启动镜像&#xff…

以当天日期时间,打包目录

#备份/data目录#!/bin/bash DATEdate %Y-%m-%d-%H:%M:%S tar cvf /mnt/resource/script/prod_master_data.$DATE.tar.gz /data[root111 script]# ll total 2536 -rw-r--r-- 1 root root 2590720 Feb 22 21:46 prod_master_data.2019-02-22-21:46:53.tar.gz转载于:https://blog.…

lvs+keepalived详解

常用软件安装及使用目录 资源链接&#xff1a;https://pan.baidu.com/s/15rFjO-EnTOyiTM7YRkbxuA 网盘分享的文件在此 官网&#xff1a;http://www.linuxvirtualserver.org/index.html 中文资料 LVS项目介绍 http://www.linuxvirtualserver.org/zh/lvs1.html …

微信自动打卡

要有第二台安卓 手机&#xff0c;打开usb、adb调试&#xff0c;永不锁屏&#xff0c;永不休眠&#xff0c;手机安装了微信并至少成功登陆过一次&#xff0c; 一台不关机的电脑&#xff0c;手机连接电脑&#xff0c;Appium服务器保持启动&#xff0c;在开始菜单 设定好任务计划程…

利用反射做类参数的校验

需求描述 业务需求描述&#xff1a;对webservice接口参数校验 代码实现 /*** 字符串长度校验* * param str* param len* return 合法(true),不合法(false)*/public static boolean check(String str, int len) {if (null ! str && str.length() > len) {return fals…

跨域的四种方式

本文主要是关于跨域的几种方式&#xff0c;关于什么是跨域这里就不多说了&#xff0c;写这个也是为了记住一些知识点的。 一. jsonp jsonp的跨域方式很容易理解&#xff0c;页面的的每一个script标签浏览器都会发送get请求获取对应的文本资源&#xff0c;获取到了之后&#xff…

Linux之read命令使用

ead命令&#xff1a; read 命令从标准输入中读取一行&#xff0c;并把输入行的每个字段的值指定给 shell 变量 1&#xff09;read后面的变量var可以只有一个&#xff0c;也可以有多个&#xff0c;这时如果输入多个数据&#xff0c;则第一个数据给第一个变量&#xff0c;第二个数…

python之路day10-命名空间和作用域、函数嵌套,作用域链、闭包

楔子 假如有一个函数&#xff0c;实现返回两个数中的较大值&#xff1a; def my_max(x,y):m x if x>y else yreturn mbigger my_max(10,20)print(bigger) 之前是不是我告诉你们要把结果return回来你们就照做了&#xff1f;可是你们有没有想过&#xff0c;我们为什么要把结…

hive(II)--sql考查的高频问题

在了解别人hive能力水平的时候&#xff0c;不管是别人问我还是我了解别人&#xff0c;有一些都是必然会问的东西。问的问题也大都大同小异。这里总结一下我遇到的那些hive方面面试可能涉及的问题 1、行转列&#xff08;列转行&#xff09; 当我们建设数据仓库时&#xff0c;我们…

java概述

一、java平台无关&#xff1a;jvm二、java健壮语言&#xff1a;无指针&#xff0c;语法上无指正&#xff0c;无内存申请与释放。 三、java核心机制而&#xff1a; jvmjava垃圾收集机制 GC四、java运行过程&#xff1a;源程序&#xff08;.java&#xff09;——》java编译器——…

时间间隔

计算当前时间与上次执行时间的时间间隔。 NSTimeInterval timetravel [[NSDate date]timeIntervalSinceDate:self.lastPlaySoundDate];if (timetravel<3.0) {DLog("时间太短&#xff0c;。。");}self.lastPlaySoundDate [NSDate date]; 转载于:https://www.cnb…

.Net+MySQL组合开发(二) 数据访问篇

一、建立数据库、表、添加数据这里我们使用图形化操作的SQL Manager 2005 Lite for MySQL来建立数据&#xff0c;它的操作界面非常类似OFFICE软件&#xff0c;使用方便、很容量上手、下面开始建立数据库及表单击"Creat New DataBase"&#xff1a;新建DB输入密码&…

Git vs SVN

一、Git vs SVN Git 和 SVN 孰优孰好&#xff0c;每个人有不同的体验。Git是分布式的&#xff0c;SVN是集中式的这是 Git 和 SVN 最大的区别。若能掌握这个概念&#xff0c;两者区别基本搞懂大半。因为 Git 是分布式的&#xff0c;所以 Git 支持离线工作&#xff0c;在本地可以…

.net api 和java平台对接技术总结

这两天 一直和京东对接接口&#xff0c;我们用.net api 提供接口&#xff0c;对方用java调用&#xff0c;本来没什么问题&#xff0c;但是对方对数据安全要求特别严&#xff0c;要验签&#xff0c;于是噩梦开始了。 1、在传输的时候&#xff0c;约定传输格式&#xff1a; HttpW…

Burpsuite学习(4)

2019独角兽企业重金招聘Python工程师标准>>> burpsuite spider模块通过跟踪 HTML 和 JavaScript 以及提交的表单中的超链接来映射目标应用程序&#xff0c;它还使用了一些其他的线索&#xff0c;如目录列表&#xff0c;资源类型的注释&#xff0c;以及 robots.txt 文…

Git删除分支/恢复分支

这是https://www.cnblogs.com/utank/p/7880441.html的方法&#xff0c;虽然很老现在有点不一样&#xff0c;但总体还是能用的。 总结就是两种方法 1.用commit的id恢复 2.用reflog的头指针恢复 •删除一个已被终止的分支 如果需要删除的分支不是当前正在打开的分支&#xff0c;使…