重构的简单认识

                                                                重构的简单认识
       工作这么长时间很少有静下来写东西的时间,有三点原因,一是不太会管理自己的时间,确实忙的没有时间写,一旦有时间写了却发现很多都没有深入理解,写出来的也只是知识点记录;二是不敢写,怕误导初学者,刚开始学程序设计时,也是很依赖网络,太相信google、百度,遇到问题就开始查资料,找办法解决,常常是耽误了不少时间有的问题还是没有找到适合场景的解决办法;有的文章作者写得也不负责,把自己不理解的不知道怎么回事的写出来给大家看,有的代码也通不过,甚至提供的思路也行不通;三是工作中也遇到不少问题,笔记记得满满的,不知道自己理解的对错?查找起来也不方便,最近在看重构的东西,所以想把学到的做个小结,

分享出来,方便正在学这块的讨论提高,路过的大牛也请批评指正。

  下面想说这几个问题:
  1、什么是重构?
  2、什么情况下需要考虑到重构代码?
  3、代码味道

  4、怎么进行简单的重构

 

  重构
    重构是一套用于标识设计流程和修改代码内部结构的技术,其目的是在不修改代码行为的基础上改善代码的设计。重构是为了促进设计,为修改提供了方便,防止设计变差。简单的说就是按照一定的方法修改现有的代码,使其更加的符合面向对象的思想,提高代码的可读性、可扩展性、可复用性,进而改善设计上的不足,改进架构,提高性能。

  重构的过程,一般是先确定代码的味道,在运用适当的重构,最后对修改代码进行单元测试验证。

  重构有以下优点:
  保持代码简单;保持代码的可读性;致力于维护软件决定性的特点,比如设计、简化型、改进源代码的理解、可读性等。
  tips:其实在我们编码的时候有意无意的已经在重构代码了,比如实现一个功能时拆分成各个不同的单一功能的方法,发现重复的代码片段,变量,提取出来作为全局变量或者公共属性,编码过程中用到的硬编码,提取出来放在字典表里,或者用枚举;提供抽象类和接口,提取各类中通用的方法属性;vs中有提供了很多重构工具,比如给某一个变量或者方法 修改名称时,右键安全重命名;定义私有属性,封装字段,提取方法,移除无用的using引用等。
  
  重构的几种方式
    通常实现某一个功能时,对于新手通常是按照自己的理解和思路,一下子把功能实现,有时甚至是一个很长的方法体,当然对于知道重构理解面向对象的大牛来说,都有有自己的编程习惯,在有意无意的使用重构;大致有这几种方式,一是边编码边重构,在实现功能的过程中,发现有代码味道的地方,立马重构修改过来;二是在实现某一特定的功能时,才开始采用重构,在不影响现有功能的使用上改进代码的设计;三是采用合适的算法或者策略编写代码,有专门的人员做重构。重构也要看项目的大小,重构的问题来源,是对于新需求的变更,当需求和代码在数量上增长的时候,发现在现有代码的基础上增加功能改动比较大,在向现有方法体增加条件或者业务逻辑时,发现设计不合理时。
  tips:重构不分大小,发现有代码味道的地方随时都可以进行重构,一般的是在完成一定代码数量的基础上进行重构,不要等到整个大的项目快要发布了,才发现很多问题。
那什么情况下才开始考虑到重构呢?发现有代码味道的地方就可以开始。经常进行重构的,看到代码不顺眼就可以进行重构。   代码味道:
  (1)长的方法体
    什么样的方法才算是长的,这个没有特别的说明,一般的方法一旦负责处理的事情多于一件,或者开始通过大量的注释来解释方法的功能,或者方法体的代码占绝对的数量,查看方法体给人很混乱难理解的感觉,这说明方法可能有点长了。
 处理方法:采用“提取方法重构”,通过拆分代码,提取新的方法,使原来的长方法体由一个个实现某一个功能点的小的方法组成,这样便于方法的重用,增加了代码的可读性。
    方法参数的确定
  一般的,设计方法的原则:方法尽可能短,只负责实现一个功能,只返回一个值,传递的参数不易过多,参数不带回返回值;,设计一个方法只要确定方法的功能、参数和返回值,这个方法就很好实现了。
  (2)某个类含有太多的成员
  在实际的开发中,有专门传递数据的实体类,有专门处理具体业务逻辑的业务类,有跟数据库打交道的数据库操作类,有负责连接数据库的帮助类,有专门提供给用户操作
  的接口类,有专门负责处理字符转换、通用业务模块的类,每个类都有自己的职责;类是对属性方法对象的抽象,有的人喜欢一个类中有定义的实体,也有实现具体功能的方法;有的喜欢类中有专门的实体,单独封装处理业务,只提供必要的接口。待续。。。
  (3)新的需求和代码绝对数量上的变更
  面对新的需求,需要在现有代码基础上添加功能发现改动比较大,或者是对现有代码发现很难理解,或者感觉到代码速度快的膨胀不可控制,这个时候就应该进行重构。
  (4)代码重复
    代码重复是最常见的异味之一,常常是copy-paste的编程风格,尤其是新手没有比实现一个功能让其兴奋的了,代码重复有很多问题,修改不方便,增加代码量,程序不易扩展;当发现有相似的代码片段、模块、业务逻辑处理块,过多的条件判断,不同类中实现功能的方法类似,方法中过多的代码注释,方法中参数过多;这些都属于代码重复问题,办法就是利用“提取方法重构”。把相同的代码片段提取出来,移动到一个方法中。
  (5)无用的代码
    无用代码包括执行不到的代码,注释掉的代码,和未使用的代码。无用代码的来源:维护工作,修改一个方法实现一个新的功能,解决bug或者对代码进行重构后而留下来的未使用的代码;设计上的更改,对某个方法加条件,注释掉的代码;孤立的事件处理程序,GUI中在删除控件时,虽然该事件不会触发但是其事件代码还存在;不可见控件, 被其他控件覆盖的控件代码;using引用导入了未使用的引用;被忽略的过程返回值,用户对函数的返回值并不感兴趣,把无用的返回值换成void类型;被忽略的过程返回参数,有的不需要带回参数;局部变量未被读取,某个变量赋值但是不会被执行;同时包含get set索引器,有的属性只需要get或者set;废弃不用的元素,在进行了过多的修改和代码重构后可能有的代码片段,模块、接口、类、方法甚至是命名空间不会再使用。对于无用代码处理办法就是果断的删除。
  (6)不同类之间类似的方法(也属于代码重复)
  重构类,提取公用的方法,抽象出通用的基类。待续。。。
  (7)winform事件开发
    针对winform编程,把大部分的代码放到窗体对应的cs文件里,或者放在某一个事件处理里,代码不能更好地重用和扩展,也属于代码重复的问题。处理办法可以提取方法提取类重构。
  (8)临时变量重构
    临时变量的声明初始化,将声明靠近引用处,在需要的地方进行声明,不必要全都放在方法的顶部;通过在声明变量的同一行对该变量进行初始化,将改善代码的可读性。负担过 重的临时变量:某一个临时变量被多次使用,应进行拆除临时变量重构,每一个临时变量只负担单一角色(当然汇总变量和循环变量不需要拆分),在他们不能增加代码清晰度的时候果断的删除。
  (9)硬编码
   硬编码增加了代码理解的难度,不易修改,大家知道经过编译器编译后的代码,最终生成dll的二进制文件,在运行该程序时操作系统(os)需要把dll文件载入到内存,计算机内存过多的重定位,这将导致dll载入速度严重下降,坏的结果就是该进程总体内存使用量的显著增加。重定位:os找出所有的硬编码偏移量地址,对其进行更新基地址的过程。过多的重定位意味着os再为dll修改内存中的代码页,消耗额外的内存。可以定义统一的字典表或者neum枚举,进行统一管理。
  (10)修改已发布的接口
   对于已经发布的接口,应该在保持用户现有功能使用的基础上进行内部重构。1>保持接口稳定和紧凑;2>尽可能少且迟的发布;3>实现并坚持版本策略;4>在完成修改时使用安全重命名重构
  (11)冗赘方法,方法极短
  方法极短,没有实质性的内容,通常一个方法体几句代码行,方法的名称也无助于代码的理解。处理办法:方法内联化(与“提取方法重构”相逆)把相应的方法去掉,直接拷贝出来方法体执行。
  (12)实现功能面向过程,不能扩展
    面向过程编程:通过调用函数并对通常作为参数的数据进行操作来编写程序,这些函数返回的结果作为操作的结果;面向对象编程:通过向对象发送消息并要求完成某些操作来构建系统;这的对象是由代表状态的信息和允许访问的信息的操作而构建的,通过封装数据是隐藏的,不能直接访问,只通过内部层次控制的属性和方法才能访问,其它对象可以使用它来与对象通信;优点:在不影响现有用户使用的情况下,修改内部实现,易于维护,模块化,可重用扩展。在进行界面绑定数据时,尽可能的分离业务逻辑处理,创建重用的组件,提取类、提取方法,把业务逻辑放在类里面处理,仔细的思考设计方案,字段和属性,一点就是要保持 字段是完全私有的,并不是对象需要的所有数据都必须从外部可见。
  (13)元素的访问级别和作用域
   元素作用域:指不在不需要完全限定的情况下,可以访问该元素的代码区域,在C#中分为四个作用域,代码块、过程、模块、命名空间作用域;对代码的修改是造成过度暴露的最常见的方式。通常一个类只提供用户必要的接口,隐藏不必要的信息,大多的元素应该定义成最低访问级别,私有的;这也是体现面向对象封装的特点。
  (14)过多的using引用
  引用是一个信号,即是它们可以使用特定的程序集所提供的服务 ;描述了系统中的依赖性;解决命名冲突;模块化减少代码编写的数量;但是引用也增加了各模块、类之间的依赖性,在修改一个模块内部的实现,也会影响引用它的模块。尽可能少的使用using引用,无用的using引用果断的删除。
  (15)代码中过多的完全限定引用
  不要随意使用完全限定名。
  (16)过时的注释
  代码注释是为了方便代码的维护,他人重构。由于设计的更改,新需求的变更,过多的代码重构,注释却很少有人留意,随时更新,给后面其他人的维护和学习带来了问题;通过 注释,也可以对代码进行重构。
  (17)引用第三方的框架或者插件
    第三方插件的优点:提供了一些公开的接口,提高编程效率,组件提供了重用和封装的好机会;缺点:新版本的组件替换旧组件可能会导致应用程序出现故障,所以尽可能选择大的 开源的稳定的第三方构架,要确保插件的改动不会影响到系统功能的使用。
  (18)混乱的命名

    良好的命名,增加了代码的可读性和易维护性,推荐《代码大全》讲的比较详细,编码的过程中也是要注意的地方。C#中约定的一些命名规则, 异常类,后面加上Exception;特性类后缀Attribute;事件后缀EnventHandler;事件参数后缀EventArgs;接口统一大写;避免使用匈牙利命名法;变量方法属性命名时,尽可能的用常用的词汇表、问题域中、文档中出现的,约定的词汇;将解决方法的词汇表用作标示符的来源;选择易于发音理解不会太长的单词,一般的用名词和动词,使用名词或者形容词给属性命名,使用名词表示对象和类的名称,使用动词给方法命名;尽可能的选择使用类的继承层次上的名称。

    以上是对重构的简单认识,重构类,抽象出通用的基类,使用接口,提取方法重构参数的问题,vs提供的重构,一些好的重构工具,后面会逐步完善补充上去。

posted on 2013-11-17 20:19  yss小虾米  阅读(307)  评论(1编辑  收藏  举报

导航