范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

重构代码坏味道

  Divergent Change(发散式变化)
  1、官方解释:
  我们希望软件能够更容易被修改——毕竟软件再怎么说本来就该是「软」的。一旦需要修改,我们希望能够跳到系统的某一点,只在该处做修改。如果不能做到这点,你就嗅出两种紧密相关的刺鼻味道中的一种了。
  如果某个class经常因为不同的原因在不同的方向上发生变化,Divergent Change就出现了。当你看着一个class说:『呃,如果新加入一个数据库,我必须修改这三个函数;如果新出现一种金融工具,我必须修改这四个函数』,那么此时也许将这个对象分成两个会更好,这么一来每个对象就可以只因一种变化而需要修改。当然,往往只有在加入新数据库或新金融工具后,你才能发现这一点。针对某一外界 变化的所有相应修改,都只应该发生在单一class中,而这个新class内的所有内容都应该反应该外界变化。为此,你应该找出因着某特定原因而造成的所有变化,然后运用Extract Class 将它们提炼到另一个class中。
  2、通俗来讲:
  由于代码的各种修改或扩展,每次都要修改某个类
  3、坏处:
  可扩展性差,某个类干的事过多。
  4、目标:
  针对某一外界变化的所有相应修改,都只发生在单一类中。这个类内的所有内容都应该反应此变化。
  5、实现方法:
  在代码的不断更迭中,多注意看哪些类经常会因为更迭而修改 。
  把这些经常变化的类独立出来,提取成单一类,专门负责此种类型的修改,考虑使用 Extract Class(提取类),降低不同的代码修改和扩展时造成同一个类不断的被修改。
  Shotgun Surgery(散弹式修改)
  1、官方解释:
  Shotgun Surgery类似Divergent Change,但恰恰相反。如果每遇到某种变化,你都必须在许多不同的classes内做出许多小修改以响应之,你所面临的坏味道就是Shotgun Surgery。如果需要修改的代码散布四处,你不但很难找到它们,也很容易忘记某个重要的修改。
  这种情况下你应该使用Move Method 和 Move Field 把所有需要修改的代码放进同一个class。如果眼下没有合适的可以安置这些代码,就创造一 个。通常你可以运用Inline Class 把一系列相关行为放进同一个class。这可能会造成少量Divergent Change,但你可以轻易处理它。
  Divergent Change是指「一个class受多种变化的影响」,Shotgun Surgery则是指「一种变化引发多个classes相应修改」。这两种情况下你都会希望整理代码,取得「外界变化」与「待改类」呈现一对一关系的理想境地。
  2、通俗来讲:
  牵一发而动全身,每次遇到某种变化,都必须在不同的类中做出小修改
  3、坏处:
  代码散步各处,不利于扩展和阅读,增加代码修改难度及工作量
  4、目标:
  尽量使某类变化通过某个特定类来处理,避免修改过多类。提升代码可扩展性,减少不必要的工作量。
  5、实现方法:
  考虑使用Move Method(搬移函数) 和Move Field(搬移字段) 把所有需要修改的代码放进同一个类。如果没有合适的类,就新建一个,考虑使用Inline Class(将类内联) 把一系列相关行为放进同一个类,这有可能造成Divergent Change(上篇讲到过)。
  此种情况与上篇所述的Divergent Change情况正好相反。
  6、本文涉及的重构方法
  Inline Class (将类内联化)
  作用:
  把某个做很少事且未来扩展可能性较为低的类合并到另一个类中。清除不必要的类,提升代码质量。
  步骤:
  利用Move Method(搬移函数) 和 Move Field(搬移字段) 把源类搬到需要搬到的目标类中
  修改原来类内的引用,调整函数及变量的作用域
  编译,测试。
  重构思路:
  把不必要的,做的事过少,并且未来扩展的可能性也较小的类合并到另一个经常引用,或者抽象概念上,可以分为一类的类中。
  建议:
  使用前考虑此类未来是否可能进行扩展,咨询同事等确认,以免无效劳动。
  Move Field (搬移字段) 与Move Method(搬移函数)
  重构思路:
  搬移字段:
  类中的某个字段比起自己类里,在另一个类中的使用频率更高,把此字段搬移到那个类中。使用此方法也需注意各个类的职责,并评估未来变化。
  搬移函数
  类中的某个函数比起自己类里,在另一个类中的使用频率更高,把此函数搬移到那个类中。使用此方法也需注意各个类的职责,并评估未来变化。
  Feature Envy(依恋情结)
  官方解释:
  对象技术的全部要点在于:这是一种「将数据和加诸其上的操作行为包装在一起」 的技术。有一种经典气味是:函数对某个class的兴趣高过对自己所处之host class的兴趣。这种孺慕之情最通常的焦点便是数据。无数次经验里,我们看到某个函数 为了计算某值,从另一个对象那儿调用几乎半打的取值函数(getting method)。疗法显而易见:把这个函数移至另一个地点。你应该使用Move Method 把它 移到它该去的地方。有时候函数中只有一部分受这种依恋之苦,这时候你应该使用 Extract Method 把这一部分提炼到独立函数中,再使用Move Method 带它去它的梦中家园。
  当然,并非所有情况都这么简单。一个函数往往会用上数个特性,那么它究竟该被置于何处呢?我们的原则是:判断哪个class拥有最多「被此函数使用」的数据,然后就把这个函数和那些数据摆在一起。如果先以Extract Method 将这个函数分解为数个较小函数并分别置放于不同地点,上述步骤也就比较容易完成了。
  有数个复杂精巧的模式(patterns)破坏了这个规则。说起这个话题,「四巨头」[Gang of Four]的Strategy 和Visitor立刻跳入我的脑海,Kent Beck 的 Self Delegation [Beck]也在此列。使用这些模式是为了对抗坏味道Divergent Change。最根本的原则是:将总是一起变化的东西放在一块儿。「数据」和「引用这些数据」的行为总是一起变化的,但也有例外。如果例外出现,我们就搬移那些行为,保持「变化只在一地发生」。Strategy 和Visitor『使你得以轻松修改函数行为,因为它们将少量需被覆写〔overridden)的行为隔离开来——当然也付出了「多一层间接性」的 代价。
  通俗来讲:
  某个函数为了实现其功能,经常从另一个类中获取大量数据。比起自身所在的类来说,更加依赖于另一个类
  坏处:
  代码结构混乱,类分功不明确,可能造成其他坏味道。
  目标:
  确定类的具体作用,并合理摆置每个函数所在的类。
  实现方法:
  考虑使用Move Method(搬移函数),如果只有函数内的一部分特别依赖其他类,先使用Extract Method(提炼函数), 再考虑使用Move Method(搬移函数)。
  如果一个函数用到了多个类的功能,那需要判断哪个类拥有最多被此函数使用的数据,把这个函数和数据摆在一起,使用Extract Method(提炼函数) 将函数分解为数个较小的函数,并分别放置在不同的位置。
  如果某些设计模式(比如策略模式,委托模式)看起来破坏了此规矩,考虑将总是变化的部分和不怎么变化的部分分开,保持变化只在一地发生。
  Data Clumps(数据泥团)
  官方解释:
  数据项(data items)就像小孩子:喜欢成群结队地待在一块儿。你常常可以在很多地方看到相同的三或四笔数据项:两个classes内的相同值域(field)、许多函数签名式(signature)中的相同参数。这些「总是绑在一起出现的数据」真应该放进属于它们自己的对象中。首先请找出这些数据的值域形式(field)出现点,运用Extract Class 将它们提炼到一个独立对象中。然后将注意力转移到函数签名式(signature)上头,运用Introduce Parameter Object 或Preserve Whole Object 为它减肥。这么做的直接好处是可以将很多参数列缩短,简化函数调用动作。是的,不必因为Data Clumps只用上新对象的一部分值域而在意,只要你以新对象取代两个(或更多)值域,你就值回票价了。
  一个好的评断办法是:删掉众多数据中的一笔。其他数据有没有因而失去意义?如果它们不再有意义,这就是个明确信号:你应该为它们产生一个新对象。
  缩短值域个数和参数个数,当然可以去除一些坏味道,但更重要的是:一旦拥有新对象,你就有机会让程序散发出一种芳香。得到新对象后,你就可以着手寻找Feature Envy,这可以帮你指出「可移至新class」中的种种程序行为。不必太久, 所有classes都将在它们的小小社会中充分发挥自己的生产力。
  通俗来讲:
  多个类中重复出现的字段,或多个函数(方法)中相同的入参。
  坏处:
  重复参数多,影响阅读和理解。
  目标:
  减少相同的字段及入参,缩短入参列,简化函数调用
  实现方法:
  找出这些重复的入参,考虑使用Extract Class(提炼类), 把这些入参放到同一个类中,然后函数的入参替换为此类,入参问题可以考虑使用 Introduce Parameter object (引入参数对象) 和 **Preserve Whole Object (保持对象完整)**来处理。
  处理完以后,就可以寻找Feature Envy(依恋情结)(见上篇),来进一步重构代码。
  Primitive Obsession(基本型别偏执)
  官方解释:
  大多数编程环境都有两种数据:结构型别(record types)允许你将数据组织成有意义的形式;基本型别(Primitive type)则是构成结构型别的积木块。结构总是会带 来一定的额外开销。它们有点像数据库中的表格,或是那些得不偿失(只为做一两件事而创建,却付出太大额外开销〕的东西。
  对象的一个极具价值的东西是:它们模糊(甚至打破)了横亘于基本数据和体积较大的classes之间的界限。你可以轻松编写出一些与语言内置(基本〕型别无异的小型classes。例如Java就以基本型别表示数值,而以class表示字符串和日期——这 两个型别在其他许多编程环境中都以基本型别表现。
  对象技术的新手通常不愿意在小任务上运用小对象——像是结合数值和币别的 money classes 、含一个起始值和一个结束值的range classes、电话号码或邮政编码(ZIP) 等等的特殊strings。你可以运用Replace Data Value with Object 将原本单独存在的数据值替换为对象,从而走出传统的洞窟,进入炙手可热的对象世界。如果欲替换之数据值是 type code(型别码),而它并不影响行为,你可以运用 Replace Type Code with Class 将它换掉。如果你有相依于此 type code的条件式,可运用 Replace Type Code with Subclasses 或 Replace Type Code with State/Strategy 加以处理。
  如果你有一组应该总是被放在一起的值域(fields),可运用Extract Class。 如果你在参数列中看到基本型数据,不妨试试Introduce Parameter Object。 如果你发现自己正从array中挑选数据,可运用Replace Array with Object。
  通俗来讲:
  以类代替原本单独存在的数值
  坏处:
  单独存在的数值不易于理解,也不符合面向对象的思想。
  目标:
  使数值尽量用类代替,就像java中的基本类型那样。
  实现方法:
  单独存在的数据值,考虑使用Replace Data Value with Object (以对象取代数据值)
  如果想要替换的数据值是类型码,而这些类型码并不影响行为,则可以运用Replace Type Code with Class (以类取代类型码)
  如果有与类型码相关的条件表达式,可运用Replace Type Code with Subclass (以子类替代类型码) 或 Replace Type Code with State/Strategy(以状态/策略取代类型码)。
  如果有一组总是放在一起的字段,可运用Extract Class(提取类)
  如果你在参数列中看到基本型数据,试试Introduce Parameter Object
  Switch Statements(switch惊悚现身)
  官方解释:
  面向对象程序的一个最明显特征就是:少用switch (或case)语句。从本质上说, switch语句的问题在于重复(duplication)。你常会发现同样的switch语句散布 于不同地点。如果要为它添加一个新的子句,你必须找到所有switch语句 并修改它们。面向对象中的多态(polymorphism )概念可为此带来优雅的解决办法。
  大多数时候,一看到switch语句你就应该考虑以「多态」来替换它。问题是态 该出现在哪儿?switch语句常常根据 type code(型别码)进行选择,你要的是「与 该 type code相关的函数或class」。所以你应该使用Extract Method 将switch语句提炼到一个独立函数中,再以Move Method 将它搬移到需要多态性的那个class里头。此时你必须决定是否使用 Replace Type Code with Subclasses 或 Replace Type Code with State/Strategy。一旦这样完成继承结构之后, 你就可以运用Replace Conditional with Polymorphism了。
  如果你只是在单一函数中有些选择事例,而你并不想改动它们,那么「多态」就有 点杀鸡用牛刀了。这种情况下Replace Parameter with Explicit Methods是个不错的选择。如果你的选择条件之一是null,可以试试Introduce Null Object。
  通俗来讲:
  少用switch语句,尽量用多态取代
  坏处:
  switch带来代码重复的问题
  目标:
  使用多态代替switch
  实现方法:
  如果需要根据类型码进行选择,使用Extract Method(提炼函数),在使用**Move Method(搬移函数)**搬到需要改为多态性的类中。
  之后,可以考虑使用Replace Type Code with Subclasses(以子类代替类型码) 或 Replace Type Code with State/Strategy(用状态或策略模式代替类型码)
  完成了前面的步骤,就可运用Replace Conditional with Polymorphism (使用多态代替条件语句) 来消除switch了。
  如果想要替换的数据值是类型码,而这些类型码并不影响行为,则可以运用Replace Type Code with Class (以类取代类型码)
  如果有与类型码相关的条件表达式,可运用Replace Type Code with Subclass (以子类替代类型码) 或 Replace Type Code with State/Strategy(以状态/策略取代类型码)。
  如果switch语句并不多,就不宜使用多态方式了,这时候可以考虑使用Replace Parameter with Explicit Methods(以明确的函数取代参数)。
  如果选择的条件中,有null的,可以试试Introduce Null Object(引入Null对象)
  Parallel Inheritance Hierarchies(平行继承体系)
  官方解释:
  Parallel Inheritance Hierarchies其实是shotgun surgery的特殊情况。在这种情况下,每当你为某个class增加一个subclass,必须也为另一个class相应增加一个subclass。如果你发现某个继承体系的名称前缀和另一个继承体系的名称前缀完全相同,便是闻到了这种坏味道。
  消除这种重复性的一般策略是:让一个继承体系的实体(instance)指涉(参考、引用、refer to)另一个继承体系的实体(instances)。如果再接再厉运用Move Method 和 Move Field,就可以将指涉端( referring class )的继承体系消弭于无形。
  通俗来讲:
  每当为一个类增加子类时,必须也为另一个类相应增加子类。
  坏处:
  重复的类
  目标:
  让其中一个继承体系的实例引用另一个继承体系的实例,减少平行继承的类。
  实现方法:
  让其中一个继承体系的实例引用另一个继承体系的实例
  使用Move Method (搬移函数) 和**Move Field(搬移字段)**消除引用,最终这些平行继承的类。
  Lazy Class(冗赘类)
  官方解释:
  你所创建的每一个class,都得有人去理解它、维护它,这些工作都是要花钱的。如 果一个class的所得不值其身价,它就应该消失。项目中经常会出现这样的情况: 某个class原本对得起自己的身价,但重构使它身形缩水,不再做那么多工作;或开发者事前规划了某些变化,并添加一个class来应付这些变化,但变化实际上没 有发生。不论上述哪一种原因,请让这个class庄严赴义吧。如果某些subclass没有做满足够工作,试试 Collapse Hierarchy。对于几乎没用的组件,你应该以Inline Class对付它们。
  通俗来讲:
  一个类用处少或者已经无用了
  坏处:
  多余的类不利于程序维护
  目标:
  消除这些多余的类
  实现方法:
  如果是某些子类没有做足够的工作,使用Collapse Hierarchy (折叠继承体系)
  其他没用的类,使用Inline Class (将类合并) 。
  Speculative Generality(夸夸其谈未来性)
  官方解释:
  这个令我们十分敏感的坏味道,命名者是Brian Foote。当有人说『噢,我想我们总有一天需要做这事』并因而企图以各式各样的挂勾(hooks)和特殊情况来处理一 些非必要的事情,这种坏味道就出现了。那么做的结果往往造成系统更难理解和维护。如果所有装置都会被用到,那就值得那么做;如果用不到,就不值得。用不上的装置只会挡你的路,所以,把它搬开吧。
  如果你的某个abstract class其实没有太大作用,请运用Collapse Hierarchy。非必要之delegation (委托)可运用Inline Class 除掉。如果函数的某些参数未被用上,可对它实施 Remove Parameter。如果函数名称带有多余的抽象意味,应该对它实施Rename Method 让它现实一些。
  如果函数或class的惟一用户是test cases (测试用例),这就飘出了坏味道Speculative Generality。如果你发现这样的函数或class,请把它们连同其test cases都删掉。但如果它们的用途是帮助test cases检测正当功能,当然必须刀下留人。
  通俗来讲:
  高估未来的扩展性,添加过多不必要的类,方法或继承体系
  坏处:
  不利于程序维护,可读性差
  目标:
  依现实来重新评估,去除多余的代码部分。
  实现方法:
  使用Collapse Hierarchy (折叠继承体系) 和 Inline Class (将类合并) 。
  如果函数中某些参数没有用到,考虑使用Remove Parameter (移除参数)
  如果函数名称过于抽象,可以使用Rename Method (重命名函数)
  Temporary Field(令人迷惑的暂时值域)
  官方解释:
  有时你会看到这样的对象:其内某个instance变量仅为某种特定情势而设。这样的代码让人不易理解,因为你通常认为对象在所有时候都需要它的所有变量。在变量未被使用的情况下猜测当初其设置目的,会让你发疯。
  请使用 Extract Class 给这个可怜的孤儿创造一个家,然后把所有和这个变 量相关的代码都放进这个新家。也许你还可以使用 Introduce Null Object 在「变量不合法』的情况下创建一个Null对象,从而避免写出『条件式代码」。
  如果class中有一个复杂算法,需要好几个变量,往往就可能导致坏味道Temporary Field的出现。由于实现者不希望传递一长串参数(想想为什么),所以他把这些 参数都放进值域(field)中。但是这些值域只在使用该算法时才有效,其他情况下只会让人迷惑。这时候你可以利用 Extract Class 把这些变量和其相关函数提炼到一个独立class中。提炼后的新对象将是一个method object[Beck](译注:其存在只是为了提供调用函数的途径,class本身并无抽象意味)。
  通俗来讲:
  某个实例变量仅为代码中一小部分功能临时所用而创建
  坏处:
  可读性差
  目标:
  减少代码中的临时变量
  实现方法:
  把这些变量和相关的函数使用Extract Class(提炼类), 放到新的类中,把原来引用这些临时变量的地方改为调用此新类中的函数。
  Message Chains(过度耦合的消息链)
  官方解释:
  如果你看到用户向一个对象索求(request)另一个对象,然后再向后者索求另一个对象,然后再索求另一个对象……这就是Message Chains。实际代码中你看到的可 能是一长串getThis()或一长串临时变量。采取这种方式,意味客户将与查找过程中的航行结构(structure of the navigation)紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。
  这时候你应该使用Hide Delegate。你可以在Message Chains的不同位置进行这种重构手法。理论上你可以重构Message Chains上的任何一个对象,但这么做往往会把所有中介对象(intermediate object )都变成Middle Man。通常更好的选择是:先观察Message Chains最终得到的对象是用来干什么的,看看能否以 Extract Method 把使用该对象的代码提炼到一个独立函数中,再运用Move Method 把这个函数推入Message Chains。如果这条链上的某个对象有多位客户打算航行此航线的剩余部分,就加一个函数来做这件事。
  有些人把任何函数链(method chain。译注:就是Message Chains;面向对象领域中所谓「发送消息」就是「调用函数」)都视为坏东西,我们不这样想。呵呵,我们的冷静镇定是出了名的,起码在这件事情上是这样。
  通俗来讲:
  代码中调用链过长
  坏处:
  代码耦合度高,造成代码扩展或修改困难
  目标:
  减少代码中调用链过长过复杂造成的耦合度高问题
  实现方法:
  使用 Hide Delegate(隐藏委托关系) 来减少耦合。
  在重构前,观察调用链最终得到的对象是用来干什么的,看是否能用Extract Method(提炼函数),把使用该对象的代码提炼到独立的函数中,再运用Move Method(搬移函数),在原调用链中使用这个函数。
  Middle Man(中间转手人)
  官方解释:
  对象的基本特征之一就是封装(encapsulation)——对外部世界隐藏其内部细节。封装往往伴随delegation (委托)。比如说你问主管是否有时间参加一个会议,他就把这个消息委托给他的记事簿,然后才能回答你。很好,你没必要知道这位主管到底使用传统记事簿或电子记事簿抑或秘书来记录自己的约会。
  但是人们可能过度运用delegation。你也许会看到某个class接口有一半的函数都委托给其他class,这样就是过度运用。这时你应该使用Remove Middle Man,直接和实责对象打交道。如果这样「不干实事」的函数只有少数几个,可以运用 Inline Method 把它们" Inlining",放进调用端。如果这些Middle Man还有其他行 为,你可以运用 Replace Delegation with Inheritance 把它变成实责对象的subclass,这样你既可以扩展原对象的行为,又不必负担那么多的委托动作。
  通俗来讲:
  类中的函数存在过度委托给其他对象的情况
  坏处:
  多余的代码,中间人作用小
  目标:
  委托函数过多时,减少委托,让调用者直接访问目标类进行操作
  实现方法:
  与上一篇Message Chains相反,减少委托函数
  使用**Remove Middle Man(移除中间人)**来减少无用的委托对象,
  如果委托函数只有少数几个,可以运用**Inline Method(合并函数)**来合并方法使代码更精炼。
  如果这些委托类里同时还有其他行为,可以运用Replace Delegation with Inheritance (以继承代替委托) 来重构
  Inappropriate Intimacy(狎昵关系)
  官方解释:
  有时你会看到两个classes过于亲密,花费太多时间去探究彼此的private成分。如果这发生在两个「人」之间,我们不必做卫道之士;但对于classes,我们希望它们严守清规。
  就像古代恋人一样,过份狎昵的classes必须拆散。你可以采用 Move Method 和 Move Field 帮它们划清界线,从而减少狎昵行径。你也可以看看是否运用 Change Bidirectional Association to Unidirectional 让其中一个class对另一个斩断情丝。如果两个实在是情投意合,可以运用Extract Class 把两者共同点提炼到一个安全地点,让它们坦荡地使用这个新class。或者也可以尝试运用 Hide Delegate 让另一个class来为它们传递相思情。
  继承(inheritance)往往造成过度亲密,因为subclass对superclass的了解总是超过superclass的主观愿望。如果你觉得该让这个孩子独自生活了,请运用Replace Delegation with Inheritance 让它离开继承体系。
  通俗来讲:
  两个类间互相依赖,总是调用对方的过多属性。
  坏处:
  代码耦合度高,破坏类的独立性
  目标:
  把联系过分紧密部分搬移或者建立新类放在其中。
  实现方法:
  使用Move Method(搬移函数) 和 Move Field(搬移字段) 来使字段或函数放在正确的位置,避免2个类之间过多的交互。
  也可以尝试使用 Change Bidirectional Association to Unidirectional (将双向关联改为单向关联) 来减少耦合。
  如果两个类实在分离不开,使用 Extract Class(提炼类) 把两者合并到一块。也可以尝试 Hide Delegate(隐藏委托关系) 把互相之间的访问委托给第三方来斩断直接的访问。
  如果是继承关系,子类不需要父类中过多的内容,运用 Replace Inheritance with Delegation(用委托代替继承) 来处理不恰当的继承关系。
  Alternative Classes with Different Interfaces(异曲同工的类)
  官方解释:
  如果两个函数做同一件事,却有着不同的签名式(signatures),请运用Rename Method 根据它们的用途重新命名。但这往往不够,请反复运用Move Method 将某些行为移入classes,直到两者的协议(protocols )一致为止。如果你必须重复而赘余地移入代码才能完成这些,或许可运用Extract Superclass 为自己赎 点罪。
  通俗来讲:
  多个做几乎相同工作的函数
  坏处:
  代码重复性过高
  目标:
  把联系过分紧密部分搬移或者建立新类放在其中。
  实现方法:
  使用 Rename Method(重命名函数) 重新命名这些相同功能的函数,反复运用 Move Method(搬移函数) 将这些函数移入类,如果需要移入类的函数过多,可以考虑**Extract Superclass(提炼父类)**来减少过多赘余的属性。
  Incomplete Library Class(不完美的程序库类)
  官方解释:
  复用(reuse)常被视为对象的终极目的。我们认为这实在是过度估计了(我们只是使用而己)。但是无可否认,许多编程技术都建立在library classes (程序库类)的基础上,没人敢说是不是我们都把排序算法忘得一干二净了。
  library classes构筑者没有未卜先知的能力,我们不能因此责怪他们。毕竟我们自己也几乎总是在系统快要构筑完成的时候才能弄清楚它的设计,所以library 构筑者的任务真的很艰巨。麻烦的是library的形式(form)往往不够好,往往不可能让我们修改其中的classes使它完成我们希望完成的工作。这是否意味那些经过实践检验的战术如 Move Method 等等,如今都派不上用场了?
  幸好我们有两个专门应付这种情况的工具。如果你只想修改library classes内的一两 个函数,可以运用 Introduce Foreign Method;如果想要添加一大堆额外行为,就得运用Introduce Local Extension。
  通俗来讲:
  封装好的类库中功能不能满足实际需求
  缺憾:
  库中没有某些需求能够使用的方法函数等,封装好的库不能更改
  目标:
  解决代码不能更改造成的不便
  实现方法:
  使用 Introduce Foreign Method(引入外加函数)
  或使用 Introduce Local Extension(引入本地扩展)
  Data Class(纯稚的数据类)
  官方解释:
  所谓Data Class是指:它们拥有一些值域(fields),以及用于访问(读写〕这些值域的函数,除此之外一无长物。这样的classes只是一种「不会说话的数据容器」,它们几乎一定被其他classes过份细琐地操控着。这些classes早期可能拥有public值域,果真如此你应该在别人注意到它们之前,立刻运用Encapsulate Field 将它们封装起来。如果这些classes内含容器类的值域(collection fields),你应该 检査它们是不是得到了恰当的封装;如果没有,就运用 Encapsulate Collection 把它们封装起来。对于那些不该被其他classes修改的值域,请运用 Remove Setting Method。
  然后,找出这些「取值/设值」函数(getting and setting methods)被其他classes运用的地点。尝试以Move Method 把那些调用行为搬移到Data Class来。如果无法搬移整个函数,就运用 Extract Method 产生一个可被搬移的函数。不久之后你就可以运用Hide Method 把这些「取值/设值」函数隐藏起来了。
  Data Class就像小孩子。作为一个起点很好,但若要让它们像「成年(成熟)」的对象那样参与整个系统的工作,它们就必须承担一定责任。
  通俗来讲:
  只有一些字段和set/get方法,单纯用作数据存储的类。也就是POJO类。
  特点:
  这些POJO类应尽量保持纯净,解耦。
  目标:
  消除类中容易耦合的部分,使类中的字段访问根据需求决定。
  实现方法:
  如果包含public字段,使用 **Encapsulate Field(封装字段)**来私有化
  如果某些字段应该不能被修改,使用 Remove Setting Method(移除set方法)
  如果类里有Collection集合类型的字段,使用 Encapsulate Collection(封装集合类)
  Refused Bequest(被拒绝的遗贈)
  官方解释:
  Subclasses 应该继承superclasses的函数和数据。但如果它们不想或不需要继承,又该怎么办呢?它们得到所有礼物,却只从中挑选几样来玩!
  按传统说法,这就意味继承体系设计错误。你需要为这个subclass 新建一个兄弟(sibling class),再运用Push Down Method 和 Push Down Field 把所有用不到的函数下推给那兄弟。这样一来superclass就只持有所有subclasses共享的东西。常常你会听到这样的建议:所有superclasses都应该是抽象的(abstract)。
  既然使用「传统说法」这个略带贬义的词,你就可以猜到,我们不建议你这么做,起码不建议你每次都这么做。我们经常利用subclassing手法来复用一些行为,并发现这可以很好地应用于日常工作。这也是一种坏味道,我们不否认,但气味通常并不强烈。所以我们说:如果Refused Bequest引起困惑和问题,请遵循传统忠告。但不必认为你每次都得那么做。十有八九这种坏味道很淡,不值得理睬。
  如果subclass复用了superclass的行为(实现),却又不愿意支持superclass的接口,Refused Bequest的坏味道就会变得浓烈。拒绝继承superclass的实现,这一点我们不介意;但如果拒绝继承superclass的接口,我们不以为然。不过即使你不愿意继承接口,也不要胡乱修改继承体系,你应该运用Replace Inheritance with Delegation 来达到目的。
  通俗来讲:
  继承某个类的子类,并不需要父类的某些方法,属性或不需要实现父类实现的接口
  缺点:
  不必要的继承关系
  目标:
  消除不必要的继承关系,使子类掌握父类需要的方法或字段。
  实现方法:
  使用Push Down Method(下移方法) 和 Push Down Field(下移字段) 来让子类拥有只有子类需要的方法或字段。
  如果子类服用了父类的方法,却不愿意支持父类的接口,考虑运用Replace Inheritance with Delegation (以委托代替继承)。
  Comments(过多的注释)
  官方解释:
  别担心,我们并不是说你不该写注释。从嗅觉上说,Comments不是一种坏味道;事实上它们还是一种香味呢。我们之所以要在这里提到Comments,因为人们常把它当作除臭剂来使用。常常会有这样的情况:你看到一段代码有着长长的注释,然后发现,这些注释之所以存在乃是因为代码很糟糕。这种情况的发生次数之多,实 在令人吃惊。
  Comments可以带我们找到本章先前提到的各种坏味道。找到坏味道后,我们首先应该以各种重构手法把坏味道去除。完成之后我们常常会发现:注释已经变得多余了,因为代码已经清楚说明了一切。
  如果你需要注释来解释一块代码做了什么,试试 Extract Method;如果method已经提炼出来,但还是需要注释来解释其行为,试试Rename Method;如果你需要注释说明某些系统的需求规格,试试 Introduce Assertion。
  TIP:当你感觉需要撰写注释,请先尝试重构,试着让所有注释都变得多余。
  如果你不知道该做什么,这才是注释的良好运用时机。除了用来记述将来的打算之外,注释还可以用来标记你并无十足把握的区域。你可以在注释里写下自己「为什 么做某某事」。这类信息可以帮助将来的修改者,尤其是那些健忘的家伙。
  通俗来讲:
  避免写不必要的注释,与其大段的写注释,不如使代码变得更加易读易懂。
  在写注释前,先考虑能否通过重构的方式让代码不需要加不必要的注释。
  注释主要起到提醒和引导的作用,不可滥用。
  缺点:
  多余且不必要的注释
  目标:
  注释前,先考虑通过重构消除不必要的注释。
  实现方法:
  Extract Method(方法提炼)
  Rename Method(方法重命名)
  Introduce Assertion (断言引入) :可以参考别人的好文章
  参考:
  https://blog.csdn.net/HermaeuxMora/article/details/83063598
  https://www.kancloud.cn/sstd521/refactor/194210
  来源:https://www.cnblogs.com/l199616j/p/15635273.html

运动武装我们的身体,全力保健康说到体育运动,上学期间,我并不喜欢。每当有体育课,还不能逃课,不过每次跑步比赛我都跑得很慢,都是最后几名。毕业以后,还很年轻,而且身体也好,所以就很少关注和加强自己的锻炼。身体状态改善工作场所健康的5个技巧传统上,工作场所经理最重要的作用是帮助组织优化其资源。现在,弹性可持续性和员工安全是公司议程的首要任务。随着办公室的动态变化,工作场所经理面临着向办公室用户提供丰富的安全和弹性服务小心点!物联网如何确保儿童在厨房中的安全数字化转型全面加速。在最近的一份报告中,麦肯锡将这一技术临界点称为加速,这表明数字技术的采用在短短几个月的时间里已经向前跃进了几年。其中一项技术是边缘计算,它是长期存在的。从智慧城碳排放时代厨房饮食餐厅服务行业的机遇DecarbonizingKitchensOpportunitiesfortheFoodServiceSectorbyBetterBuildings,U。S。DepartmentoParksAssociates55的美国宽带家庭拥有联网健康设备ParksAssociates近日将举办两场线上会议,内容涵盖独立生活解决方案和新技术,作为第八届年度互联健康峰会的一部分消费者参与和创新。这场由Alarm。comEssence和云存储即服务大容量数据存储和管理的新方法当今的企业需要一种新方法来改进其数据存储和管理不仅要推动其数字化转型,还要主动从数据中获取更多价值。跨行业数据的存储管理保护和评估都已成为关键的业务需求,在新的远程现实中更是如此。最便宜的苹果跟踪神器,能实现实时跟踪吗?关注公众号,回复抽奖即可参与抽奖活动!百元现金红包,视频课程,等众多福利等你来领取哦!苹果最近出了一个新品AirTag,售价229元。到底是智商收割机,还是物美价廉使用亲民小产品?特斯拉再次提高了3型和Y型的价格,使网络卡车成为最便宜的汽车特斯拉本周在周四晚上召开的股东大会之前,该公司已经上调了其最高销量车型的价格。调整数包括增加2000美元型号3标准范围加,将模型3的入口价格提高到41,990美元,再加上目的地费。诺基亚与沃达丰演示表明单根光纤传输容量可达70Tbps诺基亚和沃达丰土耳其最近进行的一项演示表明能够将网络容量增加到每根光纤70Tbps。诺基亚表示,它与沃达丰土耳其合作,通过后者的实时光纤网络展示了每通道1Tbps的相干传输。合作伙iPhone后封机也有好货,概率低拼运气而已开门见山,直接说一下什么是后封机,后封机主要是针对原封机来讲的,在包装方式质量保修方面有差异,下面主要从三个方面介绍一下。1后封机是手机与包装分开邮寄过来的,一般都是手机提前能到,送一款最合适的母亲节礼物莱克立式吸尘器让她更轻松三十而已火了很长一段时间,作为步入家庭集体生活的90后女性来说,既要顾家也要尽心工作,让自己疲惫不堪。尽管人生中开始过上了母亲节,最渴望的是孩子一声妈妈辛苦了,但更多的90后年轻妈
阿里供应链有着什么骗局?月入多少多少的是真的吗?本文来自坤坤(zkj2001627)未经允许禁止转载大家好,我是电商坤坤,今天是周一,又来给大家分享文章了。我写这篇文章可能会触及到某些团长的利益,所以一定要点赞关注收藏这篇文章,迈向元宇宙!Facebook推出虚拟现实工作室仅仅过去了一个月的时间,Facebook就已经开始兑现它的元宇宙承诺!上周四,Facebook旗下的Oculus正式推出了虚拟远程办公应用HorizonWorkrooms,此举也被便携小巧自带苹果线适合送妹子的充电宝绿联PD20W移动电源大家好,我是晓飞影!一个数码爱好者,也喜欢在众多平行领域探究摸索,让生活多一点乐趣。手机在生活中扮演的角色越来越重要,在重度使用的人群中,没有一款手机的续航是完全让人放心的,所以移未卜先知?数据安全法9月实施,魅族Flyme9抢先体检各大APP手机硬件配置的不断提升,使得在移动办公场景下,手机成为了主力办公工具,从而也致使不少公司开始给员工发配手机,来满足员工的办公需求,此时手机上就会存留各种隐私信息,这些信息也成为了各gaussdb200数据类型数值类型整数类型创建具有TINYINT,INTEGER,BIGINT类型数据的表。CREATETABLEmyschema。inttypet2(aTINYINT,bTINYINT,c三款1亿像素手机推荐,低至1399元起,有两款搭载骁龙870处理器不难发现如今的手机摄像头越来越多,而且像素也越来越高了,目前手机行业中,1。08亿像素是最高像素,1亿像素的优势,就是细节表现,照片在放大后依旧能保证清晰,细节也得以最大程度的保留从阿里云擅自泄露用户注册信息,再谈个人信息安全近日,一份浙江省通信管理局编号为2021483号的答复函引起了大家的关注,答复函内容为此前阿里云计算有限公司未经用户同意擅自将用户留存在的注册信息泄露给第三方合作公司。浙江省通信管铝厂不用铝,IQUNIXA80探索机三模机械键盘开箱体验写在前面IQUNIX,主打桌面周边产品,如mini机箱笔记本支架手机支架笔筒机械键盘等等,产品大多采用铝制外壳,故网友们称呼它为铝厂。IQUNIX的机械键盘,除了铝壳,颜值也非常高三星新款折叠屏维修报价出炉,维修价足以购买一部高端机?三星在前些时间里推出的折叠屏GalaxyZFold3与GalaxyZFlip3中,通过售价来看已经比前一代大幅降低,其中GalaxyZFlip3的价格基本上与GalaxyS21已经有了电动牙刷,还有必要入手冲牙器吗?素诺C3Pro冲牙器评测有了电动牙刷,还有必要试试冲牙器吗?讲实话,我个人认为电动牙刷是家具用清洁牙齿的工具中的天花板了但这仅限于在没有体验到素诺C3Pro这款冲牙器产品前。冲牙器这是一个很专业的词语,听这次能买得起了?索尼被曝将发布新机,售价仅2000多遥想当年索尼也是国内市场最常见的智能手机品牌之一,不过,虽然现在的索尼手机已经全面退守,高端机市场,却依然活得很好,且拥有不少忠实粉丝,只是售价比苹果有过之无不及,比如上半年发布的