重构-改善既有代码的设计:类数据-重新组织数据的16种方法(六)

本文深入探讨了重构数据组织与优化面向对象设计的关键步骤,包括封装字段、对象取代数值成员、值对象与引用对象转换、数组与对象替换、复制被监视数据、字面常量与符号常量的使用,以及关联关系的双向与单向转换。旨在提升代码的可读性、减少耦合度与提高模块化水平。
重新组织数据:
一、类成员变量相关:封装字段、对象取代数值成员、封装字段为public、封装集合成员、值对象改为引用对象。
二、方法的局部变量:对象取代数组、字面常用取代魔法数。
三、成员变量之间的关联关系:单向和双向之间的关联
四、重构出新类或者去掉类:类/子类取代类型码、状态/策略取代策略

目录

1.Self Encapsulate Field 自封装字段为字段建立取值get/设值set函数,并且只以这些函数来访问字段。

2. Replace Data Value with Object 对象取代数据值:类似基本类型偏执。

3.Change value to Reference 将值对象改为引用对象

4. Change Reference to Value 将引用对象改为值对象

5.Replace Array with Object 以对象取代数组:数组的元素各自代表不同的东西。以对象替换数组。

6. Duplicate Observed data 复制被监视数据:GUI相关

7.Change Unidirection Association to Bidirectional 将单向关联改为双向关联

8.Change Bidirectional  Association to Unidirection将双向关联改为单向关联

9.Replace Magic Number with Symbolic Constant字面常量取代魔法数:创建一个有意义的常量。

10.Encapsulate Field 封装字段:将类的public字段声明为private,并且提供相应的访问函数。

11.Encapsulate Coolection 封装集合:类有一个集合类型字段,在这个类中提供添加/移除集合元素的函数。

12.Replace Record with Data Class 以数据类取代记录

13. Replace Type Code with Class 以类来取代类型码:类之中有一个数值类型码,创建新的枚举类来替代。

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

15.Replace Type Code with State/Strategy 以状态/策略取代类型码:有一个类型码,它会影响类的行为,但你无法提供继承手法消除它。以状态对象取代类型码。

16.Replace Subclass with Fieldls 以字段取代子类


一、类成员变量相关


1.Self Encapsulate Field 自封装字段


间接访问类的属性:你直接访问一个字段,但与字段之间的耦合关系逐渐变得笨拙。为这个字段建立取值/设值函数,并且只以这些函数来访问字段。

       间接访问变量的好处是,子类可以通过覆写一个函数而改变获取数据的途径;它还支持更灵活的数据管理方式,例如延迟初始化。

       如果你想访问超类中的一个字段,却又想子类中将对这个变量的访问改为一个计算后的值,这就是使用Self Encapsulate Field (自封装字段)的时候。“字段自我封装”只是第一步。完成自我封装后,你可以在子类中根据自己的需要随意覆写取值/设值函数。

2. Replace Data Value with Object 对象取代数据值成员


聚合改为组合:你有一个数据项,需要与其他数据和行为一起使用才有意义。将数据项变成对象。

开发初期,你往往决定以简单的数据项表示简单的情况。但是,随着开发的进行,你可能会发现,这些简单数据项不再那么简单了。如果这样的数据项只有一两个,你还可以把相关函数放进数据项所属的对象里;但是重复代码(Duplicated Code)坏味道和 依恋情结(Feature Envy)坏味道很快就会从代码中散发出来,当这些坏味道开始出现,就应该将数据值变成对象。

3.Encapsulate Field 封装字段为private


你的类中存在一个public字段。将它声明为private,并且提供相应的访问函数。

面向对象的首要原则之一就是封装,或者称为“数据隐藏”。按此原则,你绝不应该将数据声明为public,否则其他对象就有可能访问甚至修改这项数据,而拥有该数据的对象却毫无察觉。于是,数据和行为就被分开了。

       数据声明为public被看做是一种不好的做法,因为这样会降低程序的模块化程度。数据和使用该数据的行为如果集中在一起,一旦情况发生变化,代码的修改就会比较简单,因为需要修改的代码都集中于同一块地方,而不是星罗棋布地散落在整个程序中。

       Encapsulated Field (封装字段)是封装过程的第一步,通过这项重构手法,你可以将数据隐藏起来,并通过相应的访问函数。但它毕竟只是第一步。如果一个类除了访问函数外不能提供其他行为,它终究只是一个哑巴类。这样的;类并不能享受对象技术带来的好处。实施Encapsulated Field (封装字段)之后,尝试寻找用到新建访问函数的代码,看看是否可以通过简单的 Move Method(搬移函数)将它们移到新对象去。

4.Encapsulate Coolection 成员变量是集合->封装集合


有一个函数返回一个集合。让这个函数返回该集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。

我们常常会在一个类中使用集合来保存一组实例。这样的类通常也会提供针对该集合的取值/设值函数。

       但是,集合的处理方式应该和其他种类的数据略有不同。取值函数不该返回集合自身,因为这会让用户得以修改集合内容而集合拥有者却一无所悉。也会对用户暴露过多对象内部数据结构信息。如果一个取值函数确实需要返回多个值,它应该避免用户直接操作对象内所保存的集合。并隐藏对象内与用户无关的数据结构。

       另外,不应该为这整个集合提供设值函数,但应该提供用以为集合添加/移除元素的函数。这样,集合拥有者就可以控制集合元素的添加和移除。

       如果你做到以上几点,集合就被很好地封装起来,这便可以降低集合拥有者和用户之间的耦合度。

5.Change value to Reference 将值对象改为引用对象


组合改为重数性关联(另一个类的一个对象与一个或多个该类对象有关系 Customer类对象可以包含多个order类的对象。):从一个类中衍生出许多彼此相等的实例,希望将它们替换为一个对象。将这个值对象变成引用对象。(Customer是一个实值对象,就算多份订单属于一个客户每个Order对象还是拥有各自的Customer对象。重构的结果是所有的订单对象共享一个客户名称。也就是,一个客户对象只对应一个客户名称。

    可以将对象分成两类:reference object(引用对象)和value object(实值对象)。
有一个实值对象,在其中保存了少量的不可修改的数据。你需要给这个对象加入一些可修改的数据,并确保对任何一个对象的修改都能影响到所有引用此对象的地方。这是后就需要将value object(实值对象)变成一个reference object(引用对象)。

        在许多系统中,都可以对对象做一个有用的分类:引用对象和值对象。要在引用对象和值对象之间做选择有时并不容易。有时候,你会从一个简单的值对象开始,在其中保存少量不可修改的数据。而后,你可能会希望给这个对象加入一些可修改数据,并确保对任何一个对象的修改都能影响到所引用此对象的地方。这时候你就需要将这个对象变成引用对象。

6. Change Reference to Value 将引用对象改为值对象


你有一个引用对象,很小且不可变,而且不易管理。将它变成一个值对象。

 

       要在引用对象和值对象之间做选择,有时并不容易。做出选择后,你常会需要一条回头路,

       如果引用对象开始变得难以使用,也许就应该将它改为值对象。引用对象必须被某种方式控制,你总是必须向其控制者请求适当的引用对象。它们可能造成内存区域之间错综复杂的关联。在分布式和并发系统中,不可变的值对象特别有用,因为你无需考虑它们的同步问题。

       值对象有一个非常重要的特征:它们应该是不可变的。无论何时,只有你调用同一对象的同一个查询函数,都应该得到同样结果。如果保证了这一点,就可以放心地以多个对象表示同一个事物。如果值对象是可变的,你就必须确保某个对象的修改会自动更新其他“代表相同事物”的对象。与其如此还不如把它变成引用对象。

       澄清下“不可变”(immutable)的意思:如果你以money类表示“钱’的概念,其中有”币种“和”金额“2条信息。那么Money对象通常是一个不可变的值对象。这并非意味你的薪资不能改变,而是意味:如果要改变你的薪资,就需要使用另一个Money对象来取代现有的Money对象,而不是在现有的Money对象上修改。你和Money对象之间的关系可以改变,但Money对象自身不能改变。

二、方法的局部变量


7.Replace Array with Object 以对象取代数组


你有一个数组,其中的元素各自代表不同的东西。以对象替换数组,对于数组中的每个元素,以一个字段来表示。

数组时一种常见的用以组织数据的结构。不过,它们应该只用于“以某种顺序容纳一组相似对象”。有时候你会发现,一个数组容纳了多种不同对象,这会给用户带来麻烦,因为他们很难记住像“数组的第一个元素是人名”这样的约定。对象就不同了,你可以运用字段名和函数名来传达这样的信息,因此你无需死记它,也无需依赖注释。而且如果使用对象,你还可以将信息封装起来。并使用 Move Method (搬移函数)为它加上相关行为。

8. Duplicate Observed data 复制被监视数据


你有一些领域数据置身于GUI控件中,而领域函数需要访问这些数据。将该数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。

一个分层良好的系统,应该将处理用户界面和处理业务逻辑的代码分开。之所以这样做,原因有以下几点:1)你可能需要使用不同的用户界面来表现相同的业务逻辑,如果同时承担2种责任,用户界面会变得过分复杂;2)与GUI隔离后,领域对象的维护和演化都会更容易,你甚至可以让不同的开发者负责不同部分的开发。

       尽管可以轻松地将“行为”划分到不同部位,“数据”却往往不能如此。同一项数据可能既需要内嵌于GUI控件,也需要保存于领域模型里。自从MVC模式出现后,用户界面框架都使用多层系统来提供某种机制,使你不但可以提供这类数据,并保持它们同步。

       如果你遇到的代码是以2层方式开发,业务逻辑被内嵌于用户界面之中,你就有必要将行为分离出来。其中的主要工作就是函数的分解和搬移。但数据就不同了;你不能仅仅只是移动数据,必须将它复制到新的对象中,并提供相应的同步机制。

 9.Replace Magic Number with Symbolic Constant字面常量取代魔法数


你有一个字面数值,带有特别含义。创建一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量。

        在计算科学中,魔法数是历史悠久的不良现象之一。所谓魔法数是指拥有特殊意义,却又不能明确表现出这种意义的数字。如果你需要在不同的地点引用同一个逻辑数,魔法数会让你烦恼不已,因为一旦这些数发生变化,你就必须在程序中找到所有魔法数,并将它们全部修改一遍。就算你不需要修改,要准确指出每个魔法数的用途,也会让你颇费脑筋。

       许多语言都允许声明常量。常量不会造成任何性能开销,却可以大大提高代码的可读性。

       进行本项重构之前,你应该先寻找其他替代方案。你应该观察魔法数任何被使用,而后你往往会发现一种更好的使用方式。如果这个魔法数是个类型码,请考虑使用 Replace Type Code with Class (以类取代类型码);如果这个魔法数代表一个数组的长度,请在遍历数组时,改用数组.length。

三、成员变量的关联关系


10.Change Unidirection Association to Bidirectional 将单向关联改为双向关联


两个类都需要使用对方特性,但其间只有一条单向连接。添加一个反向指针,并使修改函数能够同时更新2条连接。

   

开发初期,你可能会在2个类之间建立1条单向连接,使其中一个类可以使用另一个类。随着时间推移,你可能发现被引用类需要得到其引用者以便进行某些处理。也就是说它需要一个反向指针。但指针是一种单向连接,你不可能反向操作它。通常你可以绕道而行,虽然会耗费一些计算时间,成本还算合理,然后你可以在被引用类中建立一个函数专门负责此行为。但是,有时候想绕过这个问题并不容易,此时就需要建立双向引用关系,或称为反向指针。如果使用不当,反向指针和很容易造成混乱;但只要你习惯了这种手法,它们其实并不太复杂。

       “反向指针”手法有点棘手,所以在你能够自如运用之前,应该有相应的测试。通常不用花心思去测试访问函数,因为普通访问函数的风险没有高到需要测试的地步,但本重构要求测试访问函数,所以它是极少数需要添加测试的重构手法之一。

       本重构运用反向指针实现双向关联,其他技术需要其他重构手法。

11.Change Bidirectional  Association to Unidirection将双向关联改为单向关联


两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。 去除不必要的关联。

双向关联很有用,但你必须为它付出代价,那就是维护双向连接、确保对象被正确创建和删除而增加的复杂度。而且,由于很多程序员并不习惯使用双向关联,它往往成为错误之源。

       大量的双向连接也很容易造成“僵尸对象”:某个对象本来应该死亡了,却仍然保留在系统中,因为对它的引用没有完全清除。

       此外,双向关联也迫使2个类之间有了依赖:对其中任一个类的任何修改,都可能引发另一个类的变化。如果这2个类位于不同的程序集,这种依赖就是程序集之间的相依。过多的跨程序集依赖会造就紧耦合的系统,使得任何一点小小改动就可能造成许多无法预知的后果。

       只有在真正需要双向关联的时候,才该使用它。如果发现双向关联不再有存在价值,就应该去掉不必要的一条关联。

 

四、重构出新的数据类或者替换类


12.Replace Record with Data Class 以数据类取代记录


       你需要面对传统编程环境中的记录结构。为该记录创建一个“哑”数据对象。
       记录型结构是许多编程环境的共同性质。有一些理由使它们被带进面向对象程序之中:你可能面对的是一个遗留程序,也可能需要通过一个传统API来与记录结构交流,或是处理从数据库读出的记录。这些时候你就有必要创建一个接口类,用以处理这些外来数据。最简单的做法就是先建立一个看起来类似外部记录的类,以便日后将某些字段和函数搬移到这个类中。一个不太常见但非常令人注目的情况是:数组中的每个位置上的元素都有特定含义,这种情况下应该使用 Replace Array with Object (以对象取代数组)。

13. Replace Type Code with Class 以类来取代类型码


类之中有一个数值类型码,但它并不影响类的行为。以一个新的类替换该数值类型码。

在以C为基础的编程语言中,类型码或枚举值很常见。如果带着一个有意义的符号名,类型码的可读性还不错。问题在于,符号名终究只是个别名,编译器看见的、进行类型检验的,还是背后那个数值。任何接受类型码作为参数的函数,所期望的实际上是一个数值,无法强制使用符号名。这会大大降低代码的可读性,从而成为bug之源。

       如果把那样的数值换成一个类,编译器就可以对这个类进行类型检验。只要为这个类提供工厂函数,你就可以始终保证只有合法的实例才会被常见出来,而且他们都会被传递给正确的宿主对象。

       但是,在使用Replace Type Code with Class (以类取代类型码)之前,你应该先考虑类型码的其他替换方式。只有当类型码是纯粹数据时(也就是类型码不会在switch语句中引起行为变化时),你才能以类来取代它。更重要的是:任何switch语句都应该运用Replace Conditional with Polymorphism (以多态取代条件表达式)去掉。为了进行那样的重构,你首先必须运用 Replace Type Code with Subclass (以子类取代类型码)或Replace Type Code with State/Strategy (以状态策略取代类型码),把类型码处理掉。

       即使一个类型码不会因其数值的不同而引起行为上的差异,宿主类中的某些行为还是可能更适合放置于类型码类中,因此你还应该留意是否有必要使用Move Method(搬移函数)将一两个函数搬过去。

14.Replace Type Code with Subclasses 以子类来取代类型码


  你有一个不可变的类型码,它会影响类的行为。以子类取代这个类型码。

 

如果你面对的类型码不会影响宿主类的行为,可以使用Replace Type Code with Class (以类取代类型码)来处理它们。但如果类型码会影响宿主类的行为,那么最后的办法就是借助多态来处理变化行为。

       一般来说,这种情况的标志就是像switch这样的条件表达式。这种条件表达式可能有2种表现形式:switch语句或者if –then-else结构。不论哪种形式,它们都是检查类型码值,并根据不同的值执行不同的动作。这种情况下,你应该以 Replace Conditional with Polymorphism (以多态取代条件表达式)进行重构。但为了那个顺利进行那样的重构,首先应该将类型码替换为可拥有多态行为的继承体系。这样一个继承体系应该以类型码宿主类为基类,并针对每一种类型码建立一个子类。

       但是以下2种情况你不能那么做1)类型码值在对象创建之后发生了变化;2)由于某种原因,类型码宿主类已经有了子类。如果你恰好面临这2种情况之一,就需要运用 Replace Type Code with StateStrategy (以状态策略取代类型码)。

       Replace Type Code with Subclass (以子类取代类型码)的主要作用其实是搭建一个舞台,让Replace Conditional with Polymorphism (以多态取代条件表达式)得以一展身手。如果宿主类中并没有出现条件表达式,那么Replace Type Code with Class (以类取代类型码)更合适,风险也较低。

       使用Replace Type Code with Subclass (以子类取代类型码)的另一个原因是,宿主类中出现了“只与具备特定类型码之对象相关”的特性。完成本项重构后,你可以使用 push down Method (函数下移)和push down field (字段下移)将这些特性推到合适的子类中去,以彰显它们只与特定情况相关这一事实。

       Replace Type Code with Subclass (以子类取代类型码)的好处在于:它把“对不同行为的了解”从类用户那转移到了类自身。如果需要再加入新的行为变化,只需要添加一个子类就行了。如果没有多态机制,就必须找到所有条件表达式,并逐一修改它们。因此,如果为了还有可能加入新行为,这项重构将特别有价值。

15.Replace Type Code with State/Strategy 以状态/策略取代类型码


你有一个类型码,它会影响类的行为,但你无法提供继承手法消除它。以状态对象取代类型码。

 

本项重构和Replace Type Code with Subclass (以子类取代类型码)类似,但如果“类型码在对象生命期中发生变化”或“其他原因使得宿主类不能被继承”,你也可以使用本重构。本重构使用State模式和Strategy模式。

       State模式和Strategy模式非常相似,因此无论你选择其中哪一个,重构过程都是一样的。“选择哪个模式”并非问题的关键所在,你只需要选择更合适特定情境的模式就行了。如果你打算在完成本重构后再以Replace Conditional with Polymorphism (以多态取代条件表达式)简化一个算法,那么选择Strategy模式较合适;如果你打算搬移状态相关的数据,而且你把新建对象视为一种变迁状态,就应该选择State模式。

16.Replace Subclass with Fieldls 以字段取代子类


你的各个子类的唯一差别只在“返回常量数据”的函数身上。修改这些函数,使它们返回超类中的某个(新增)只读,然后销毁子类。

       建立子类的目的,是为了增加新特性或变化其行为。有一种变化行为被称为“常量函数”,它们会返回一个硬编码的值。这东西有其用途:你可以让不同的子类中的同一个访问函数返回不同的值。你可以在超类中将访问函数声明为抽象函数,并在不同子类中让它返回不同的值。

       尽管常量函数有其用途,但若与子类中只有常量函数,实在没有足够的存在价值。你可以在超类中设计一个与常量函数返回值相应的字段,从而完全除去这样的子类。如此一来就可以避免因继承而带来的额外复杂性。

一直很喜欢重构这本书,但是由于自己记性不太好,书看过之后其中的方法总是记不住,于是想如果有电子版的重构书就好了,工作中遇到重构的问题可以随时打开查阅。在网上搜索了许久,发现重构这本书有英文chm版本的,而中文版的电子书只有扫描的PDF版本,用起来非常不方便。于是萌生想做一本重构工具书的想法,本来打算自己重新重构书的内容再整理归类一下,后来发现原书的目录编排就很适合做工具书,包括坏味道分类,重构手法归类等,都有了一个比较系统的整理。因此,我利用空余时间制作了这样的一本中文的chm版重构,希望对大家有所帮助,也算对中国软件业做出一点小小的贡献。 本书基本上是取自”重构”中文版一书的内容,但格式上参照的是chm英文版的格式,还有一些格式小修改,比如第一章的重构前后代码对比。因为时间匆促,个人能力有限,本书难免存在一些缺漏,如果大家发现有问题,随时可以给我发邮件,我会尽快更新错误的内容。 最后再次感谢几位大师 Martin Fowler、Kent Beck等,还有翻译的侯捷和熊节先生,为我们带来这么精彩的一本书。谢谢。 免责声明:本书仅供个人学习研究之用,不得用于任何商业目的,不得以任何方式修改本作品,基于此产生的法律责任本人不承担任何连带责任。
第1章 重构,第一个案例 1 1.1 起点 1 1.2 重构的第一步 7 1.3 分解并重组statement() 8 1.4 运用多态取代与价格相关的条件逻辑 34 1.5 结语 52 第2章 重构原则 53 2.1 何谓重构 53 2.2 为何重构 55 2.3 何时重构 57 2.4 怎么对经理说 60 2.5 重构的难题 62 2.6 重构设计 66 2.7 重构与性能 69 2.8 重构起源何处 71 第3章 代码的坏味道 75 3.1 Duplicated Code(重复代码) 76 3.2 Long Method(过长函数) 76 3.3 Large Class(过大的类) 78 3.4 Long Parameter List(过长参数列) 78 3.5 Divergent Change(发散式变化) 79 3.6 Shotgun Surgery(霰弹式修改) 80 3.7 Feature Envy(依恋情结) 80 3.8 Data Clumps(数据泥团) 81 3.9 Primitive Obsession(基本类型偏执) 81 3.10 Switch Statements(switch惊悚现身) 82 3.11 Parallel InheritanceHierarchies(平行继承体系) 83 3.12 Lazy Class(冗赘类) 83 3.13 Speculative Generality(夸夸其谈未来性) 83 3.14 Temporary Field(令人迷惑的暂时字段) 84 3.15 Message Chains(过度耦合的消息链) 84 3.16 Middle Man(中间人) 85 3.17 Inappropriate Intimacy(狎昵关系) 85 3.18 Alternative Classes with Different Interfaces(异曲同工的类) 85 3.19 Incomplete Library Class(不完美的库类) 86 3.20 Data Class(纯稚的数据类) 86 3.21 Refused Bequest(被拒绝的遗赠) 87 3.22 Comments(过多的注释) 87 第4章 构筑测试体系 89 4.1 自测试代码的价值 89 4.2 JUnit测试框架 91 4.3 添加更多测试 97 第5章 重构列表 103 5.1 重构的记录格式 103 5.2 寻找引用点 105 5.3 这些重构手法有多成熟 106 第6章 重新组织函数 109 6.1 Extract Method(提炼函数) 110 6.2 Inline Method(内联函数) 117 6.3 Inline Temp(内联临时变量) 119 6.4 Replace Temp with Query(以查询取代临时变量) 120 6.5 Introduce Explaining Variable(引入解释性变量) 124 6.6 Split Temporary Variable(分解临时变量) 128 6.7 Remove Assignments to Parameters(移除对参数的赋值) 131 6.8 Replace Method with Method Object(以函数对象取代函数) 135 6.9 Substitute Algorithm(替换算法) 139 第7章 在对象之间搬移特性 141 7.1 Move Method(搬移函数) 142 7.2 Move Field(搬移字段) 146 7.3 Extract Class(提炼类) 149 7.4 Inline Class(将类内联化) 154 7.5 Hide Delegate(隐藏“委托关系”) 157 7.6 Remove Middle Man(移除中间人) 160 7.7 Introduce Foreign Method(引入外加函数) 162 7.8 Introduce Local Extension(引入本地扩展) 164 第8章 重新组织数据 169 8.1 Self Encapsulate Field(自封装字段) 171 8.2 Replace Data Value with Object(以对象取代数据值) 175 8.3 Change Value to Reference(将值对象改为引用对象) 179 8.4 Change Reference to Value(将引用对象改为值对象) 183 8.5 Replace Array with Object(以对象取代数组) 186 8.6 Duplicate Observed Data(复制“被监视数据”) 189 8.7 Change Unidirectional Association to Bidirectional(将单向关联改为双向关联) 197 8.8 Change Bidirectional Association to Unidirectional(将双向关联改为单向关联) 200 8.9 Replace Magic Number with Symbolic Constant(以字面常量取代魔法数) 204 8.10 Encapsulate Field(封装字段) 206 8.11 Encapsulate Collection(封装集合) 208 8.12 Replace Record with Data Class(以数据类取代记录) 217 8.13 Replace Type Code with Class(以类取代类型码) 218 8.14 Replace Type Code with Subclasses(以子类取代类型码) 223 8.15 Replace Type Code with State/Strategy(以State/Strategy取代类型码) 227 8.16 Replace Subclass with Fields(以字段取代子类) 232 第9章 简化条件表达式 237 9.1 Decompose Conditional(分解条件表达式) 238 9.2 Consolidate Conditional Expression(合并条件表达式) 240 9.3 Consolidate Duplicate Conditional Fragments(合并重复的条件片段) 243 9.4 Remove Control Flag(移除控制标记) 245 9.5 Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式) 250 9.6 Replace Conditional with Polymorphism(以多态取代条件表达式) 255 9.7 Introduce Null Object(引入Null对象) 260 9.8 Introduce Assertion(引入断言) 267 第10章 简化函数调用 271 10.1 Rename Method(函数改名) 273 10.2 Add Parameter(添加参数) 275 10.3 Remove Parameter(移除参数) 277 10.4 Separate Query from Modifier(将查询函数和修改函数分离) 279 10.5 Parameterize Method(令函数携带参数) 283 10.6 Replace Parameter with Explicit Methods(以明确函数取代参数) 285 10.7 Preserve Whole Object(保持对象完整) 288 10.8 Replace Parameter with Methods(以函数取代参数) 292 10.9 Introduce Parameter Object(引入参数对象) 295 10.10 Remove Setting Method(移除设值函数) 300 10.11 Hide Method(隐藏函数) 303 10.12 Replace Constructor with Factory Method(以工厂函数取代构造函数) 304 10.13 Encapsulate Downcast(封装向下转型) 308 10.14 Replace Error Code with Exception(以异常取代错误码) 310 10.15 Replace Exception with Test(以测试取代异常) 315 第11章 处理概括关系 319 11.1 Pull Up Field(字段上移) 320 11.2 Pull Up Method(函数上移) 322 11.3 Pull Up Constructor Body(构造函数本体上移) 325 11.4 Push Down Method(函数下移) 328 11.5 Push Down Field(字段下移) 329 11.6 Extract Subclass(提炼子类) 330 11.7 Extract Superclass(提炼超类) 336 11.8 Extract Interface(提炼接口) 341 11.9 Collapse Hierarchy(折叠继承体系) 344 11.10 Form Tem Plate Method(塑造模板函数) 345 11.11 Replace Inheritance with Delegation(以委托取代继承) 352 11.12 Replace Delegation with Inheritance(以继承取代委托) 355 第12章 大型重构 359 12.1 Tease Apart Inheritance(梳理并分解继承体系) 362 12.2 Convert Procedural Design to Objects(将过程化设计转化为对象设计) 368 12.3 Separate Domain from Presentation(将领域和表述/显示分离) 370 12.4 Extract Hierarchy(提炼继承体系) 375 第13章 重构,复用与现实 379 13.1 现实的检验 380 13.2 为什么开发者不愿意重构他们的程序 381 13.3 再论现实的检验 394 13.4 重构的资源和参考资料 394 13.5 从重构联想到软件复用和技术传播 395 13.6 小结 397 13.7 参考文献 397 第14章 重构工具 401 14.1 使用工具进行重构 401 14.2 重构工具的技术标准 403 14.3 重构工具的实用标准 405 14.4 小结 407 第15章 总结 409
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hguisu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值