吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2722|回复: 6
收起左侧

[Java 转载] 《重构-改善既有代码设计》【8-9】章整理学习分享(重构手法:组织数据/条件表达式)

  [复制链接]
象相合 发表于 2017-12-17 21:25
本帖最后由 象相合 于 2017-12-17 21:35 编辑

        大家好,今天继续给大家分享重构手法,以下是文章主要内容:

              1. 更新的重构原则。
              2. 重新组织数据系手法。
              3. 简化条件表达式系手法。
              4. 项目分享。
      
         随着“重构原则”的充实,整体收获并没有那么大了,因此项目分享在数据处理系后停更。相应给出比较好理解的一句话概括。
         这个编辑器有点难受,我复制自己写的发送的时候居然标题全变成1. 了。=

        一、重构原则更新:
               
  • 为即将修改的代码建立一组可靠的测试环境。
  • 临时变量助长冗长而复杂的函数。
  • 最好不要再另一个对象的属性基础上运用switch语句。如果要switch也要在类自己的数据上使用。
  • 事不过三,三则重构。
  • 首先写出可调的程序,然后调整它以求获得足够速度。
  • 一个好的名字可以省去读函数内容的操作。
  • 每当需要注释说明时,可以被写进一个函数里,并以用途命名,关键不在函数长度,而在函数做什么,怎么做。
  • 条件和循环也是提炼信号。
  • 针对外界变化的所有相应修改,应该只发生在单一类中,这个类的所有内容随外界变化。
  • 一个函数使用几个类的功能,它应该被放在最多被此函数使用的数据一起。
  • 对于出现在不同类/方法内的一些绑在一起的数据,应该给它们设置对象。
  • 少用switch,switch代表重复。
  • 两个帽子原则:不要边写代码边重构,带上写代码的帽子,觉得需要重构了,再带上重构的帽子去做,如此反复。
  • 注释多写为什么这样,过多注释不一定是好,尝试重构。
  • 先编写测试代码可以将关注点放在接口而非实现。
  • 每当出现一个BUG,先写一个测试单元测试BUG。不要修改以前的测试单元,因为它可能会在修复BUG后出错。
  • 测试:异常,边界
  • 测试太多带来的效益呈现递减态势。但是我们尽量测试大多数BUG。
  • 小步前进,频繁测试。
  • 即使想要提炼的函数非常简单,只要新函数名能更好地示意代码意图,也应该提炼它。
  • 重构出来的函数优先使用private修饰,日后可以慢慢放开。
  • 重构时可能会有性能问题,但这不是主要问题,如果没有重构,好的优化方案就可能与你失之交臂。性能实在太糟糕,临时变量放回去也很容易。
  • 临时变量如果被赋值多次,尽量使它们只使用一次。
  • JAVA只采用按值传递参数,因此对参数赋值一般不可取,不要对参数赋值。
  • public不是java的全部,java值得封装的东西有很多。
  • 先写测试,再写类。
  • 去除控制标记,语句会清晰明了。
  • “每一个函数只能有一个入口和一个出口”的观念会使人陷入代码的坏味道。
  • 条件反转有时候可以帮助写清晰的代码。
  • if then else也代表重复,尽量不要写。
  • 使用空对象可以方便的处理很多东西,它一定是常量。非常适合使用Singleton模式。

         
        二、重新组织数据系手法:

  • Self Encapsulate Field自我封装字段 196
  • 直接访问一个字段,但字段之间耦合关系逐渐笨拙:为字段生成get/set方法,以函数访问。

   2. Replace Data Value with Object以对象取代数据值 200
  • 有一个数据项,需要与其他数据和行为一起使用才有意义:将数据变成对象。


   3. Change Value to Reference将值对象改为引用对象 204
  • 一个类衍生许多彼此相等实例,需要将它们替换为同一个对象:将这个值变为引用对象。
  • 使用Replace Constructor with Facotry Method->测试->决定对象负责提供访问新对象的途径->决定引用对象预先创建好还是动态创建->修改工厂函数,令其返回引用对象->测试

   4. Change Reference to Value将引用对象改为值对象 208
  • 有一个引用对象,很小且不可变,且不易管理:将它变成一个值对象。
  • 值对象的特性,它是不可变的。
  • 使用Remove Setting Method(300)将它变为不可变->建立equalss()和hashCode()->测试->考虑删除工厂,构造声明函数为public


   5. Replace Array with Object以对象取代数组
  • 有一个数组,元素格子代表不同东西:以对象替换数组,对于数组中每个元素,以一个字段表示。


   6. Duplicate Observed Data复制“被监视数据”
  • 有一些领域数据置身于GUI控件,领域函数需要访问这些数据:将数据复制到领域对象,建立Observer模式,用以同步领域对象和GUI对象内的重复数据。


   7. Change Unidirectional Association to Bidirectional将单向关联改为双向关联
  • 两个类需要使用对方特性,但其间只有一条单向连接:添加反向指针,并使修改函数能同时更新两条连接。
  • 使用不当的话,反向指针容易造成混乱,但只要习惯这种手法,其实并不太复杂。
  • 在被引用类中增加一个字段,保存反向指针->决定由哪个类(引用端还是被引用端)控制关联关系->在被控端建立一个辅助函数,命名应指出它的有限用途->如果既有的修改函数在控制端,让它负责更新反向指针->如果在被控端,就在控制端建立一个控制函数,并让既有的修改函数调用这个新建的控制函数。


   8. Change Bidirectional Association to Unidirectional将双向关联改为单向关联 225
  • 两个类之间有双向关联,但如今其中一个类不再需要另一个类的特性。
  • 找出该去除的指针->如果使用了取值函数,先用Self Encapsulate Field将待删除字段自我封装,然后使用Subsititute Algorithm对付取值函数。->如果客户未使用取值函数,直接修改带删除字段的所有被引用点。->如果没有任何函数使用待删除字段,移除所有对字段的更新逻辑。


   9. Replace Magic Number with Symbolic Constant以字面常量取代魔法数
  • 有一个字面数值,带有特别含义:创造一个常量,根据意义命名,并将上述字面数值替换为这个常量。
  • 声明一个常量->找出引用点->检查是否可使用新声明变量替换魔法数->魔法数替换完毕,整个程序应运转如常。


   10. Encapsulate Field封装字段
  • 类中存在一个public字段:将它声明为private,并提供相应访问函数。
  • 提供get/set。


   11. Encapsulate Collection封装集合
  • 有个函数返回集合:让这个函数返回集合的只读副本,并在这个类中提供添加/移除集合元素的函数。


   12. Replace Record with Data Class以数据类取代记录
  • 需要面对传统编程环境中记录结构:为该记录创建一个哑数据对象。
  • 新建一个类表示这个记录->对于每项数据,在新建类中建立对应private字段,并提供相应取值/设值函数。


   13. Replace Type Code with Class以类取代类型码
  • 类之中一个数值类型码,但并不影响类行为:以一个新的类替换该数值类型码。


   14. Replace Type Code with Subclasses以子类取代类型码 248
  • 有一个不可变类型码,它会影响类的行为:以子类取代这个类型码。



   15. Replace Type Code with State/Strategy以State/Strategy取代类型码 252
  • 有一个类型码,会影响类的行为,但无法通过继承消除:以状态对象取代类型码。
  • 类型码抽象成类,可进行的操作就会变多。


   16. Replace Subclass with Fields以字段取代子类 257
  • 各个子类的唯一差别只在“返回常量数据”函数上:修改这些函数,使它们返回超类中某个新增字段,然后销毁子类。
  • 复杂而冗余的类关系会导致代码的坏味道。


        三、简化条件表达式系手法:

    1. Decompose Conditional分解条件表达式 263
  • 有一个复杂的条件语句:从if then else 三个段落中分别提炼出独立函数。
  • 逻辑里的东西是非常难读的,与其加一个注释不如直接Extract Method。


    2. ConsolIDAte Conditional Expression合并条件表达式 265
  • 有一系列条件测试,都得到相同效果:将这些测试合并为一个条件表达式,并将这个条件表达式提炼成独立函数。
  • 有时候有一堆if的测试也很难读,干脆把它们一起提取了。
  • 一堆if 使用或 ;if嵌套使用 与


    3. Consolidate Duplicate Coditional Fragments合并重复的条件片段 268
  • 再条件表达式的每个分支上有相同的一段代码:将这段重复代码搬移到条件表达式外。
  • 去除重复代码。


    4. Remove Control Flag移除控制标记 270
  • 在一系列bool表达式中,某个变量带有“控制标记”作用:以break语句或return 语句取代控制标记。
  • 去除控制标记,语句会清晰明了。
  • 有时候会有副作用,使用Separate Query from Modifier将副作用移除。


    5. Replace Nested Conditinal with Guard Clauses 以卫语句取代嵌套条件表达式 275
  • 函数中条件逻辑使人难以看清正常执行路径:使用卫语句表现所有特殊情况。
  • 就是不用else,全部用if/return达成一步步过滤的状态。
  • “每一个函数只能有一个入口和一个出口”的观念会使人陷入代码的坏味道。
  • 条件反转有时候可以帮助写清晰的代码。


    6. Replace Conditinal with Polymorphism 以多态取代条件表达式 280
  • 手上有个条件表达式,它根据对象类型不同选择不同行为。:将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数。
  • 就是使用多态把switch给拆开到类里面去了。


    7. Introduce Null Object引入null对象 285
  • 你需要再三检查某对象是否为Null: 将null值替换为null对象
  • 使用空对象可以方便的处理很多东西,它一定是常量。非常适合使用Singleton模式。
  • 用空对象继承原对象,原对象isNull为false空对象为true,以后.isNull()即可知道是否为空。甚至可以添加一个接口Nullable昭示大家这是一个空对象。
  • 空对象是一个特例类。


    8. Introduce Assertion引入断言 292
  • 某一段代码需要对程序状态做出某种假设:以断言明确表现这种假设
  • 使用断言“一定为真”的情况,可以帮助程序不出错,滥用断言会导致逻辑混乱。

        今天分享就到这里,祝大家学习进步!

免费评分

参与人数 1吾爱币 +15 收起 理由
萋小磊 + 15 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 象相合 发表于 2017-12-17 21:36
编辑器有毒,小BUG调的很难受。
kk1212 发表于 2017-12-17 21:42
sxtylhg 发表于 2017-12-17 22:38
mixthe 发表于 2017-12-17 23:16
笔记太正式,不像自己总结的,要用自己的话来说
L__ 发表于 2017-12-18 13:06
重构手法笔记分享不错
_vision 发表于 2017-12-22 03:26
学习了,加油!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-15 05:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表