点击上方“阿拉奇学Java”,选择“置顶或者星标”
优质文章第一时间送达!
替换为:
return(anOrder.basePrice > 1000);你的程序以一个临时变量保存某一表达式的运算结果。将这个表达式提炼到一个独立的函数中。将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可被其他函数使用。
double basePrice = quantity * timePrice; if(basePrice > 1000){ return basePrice * 09.5; } else{ return basePrice * 0.98; }替换为:
if(basePrice() > 1000){ return basePrice * 09.5; } else{ return basePrice * 0.98; } double basePrice(){ return quantity * timePrice; }临时变量只在所属的函数中可见,如果把临时变量替换为一个查询,那么同一个类中的所有函数都将可以获得这个份信息,这将带给你极大的帮助,使你能够为这个类编写更清晰的代码。
你有一个复杂的表达式。将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。
if((platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize >0){ //do smothing }替换为:
finalboolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1; finalboolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1; finalboolean wasResized = resize >0; if(isMacOs && isIEBrowser && wasInitialized() && wasResized){ //do smothing }表达式有可能非常复杂难以理解。这种情况下,临时变量可以帮助你将表达式分解为比较容易管理的形式。在条件逻辑中,你可以用这项重构将每个条件子句提炼出来,以一个良好命名的临时变量来解释对应条件子句的意义。另一种情况是:在较长的算法中,可以运用临时变量来解释每一步运算的意义。
你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。针对每次赋值,创造一个独立、对应的临时变量。
double temp = 2* (height + width); System.out.println(temp); temp = height * width; System.out.println(temp);替换为:
double perimeter = 2* (height + width); System.out.println(perimeter); double area = height * width; System.out.println(area);如果临时变量被赋值超过一次,就意味着它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换为多个临时变量。每个变量只承担一个责任,同一个临时变量承担两件不同的事情会令代码阅读者糊涂
代码对一个参数进行复制。以一个临时变量取代该参数的位置。
int discount (int inputVal, int quantity, int yearToData){ if(inputVal > 50) inputVal -= 2; }替换为:
int discount (int inputVal, int quantity, int yearToData){ int result = inputVal; if(inputVal > 50) result -= 2; }如果代码的语义是按引用传递的,请在调用段检查调用后是否还使用了这个参数。
想要把某个算法替换为另一个更清晰的算法。将函数本体替换成为另一个算法。
String foundPerson(String[] people){ for(int i = 0;i < people.length; i++){ if(people[i].equals("Don")){ return"Don"; } if(people[i].equals("John")){ return"John"; } if(people[i].equals("Kent")){ return"Kent"; } } return""; }替换为:
String foundPerson(String[] people){ List candidates = Arrays.asList(newString[]{"Don", "John", "Kent"}); for(int i = 0;i < people.length; i++){ if(candidates.contains(people[i])){ return prople[i]; } } return""; }在对象设计过程中, 决定把责任放在哪儿是即使不是最重要的事,也是最重要的事之一。常常只使用 搬移函数和 搬移字段简单地移动对象行为,就可以解决这些问题。如果这两个重构手法都需要用到,我会首先使用 搬移字段,再使用 搬移方法。如果一个类承担了太多责任而变得臃肿不堪,这种情况下会使用 提炼类将一部分责任分离出去。如果一个类变得太不负责任,使用 将类内联化将它融入到另一个类中。
你的程序中,有个函数与其所驻类之外的另个一类进行跟过的交流:调用后者或被后者调用。在该函数最长引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或者将旧函数完全移除。如果一个类有太多行为,或如果一个类与另一个类有太多合作而高度耦合,就需要搬移函数。可以是系统中的类更简单
程序中,某个字段被其所驻类之外的另一个类更多的用到。在目标类新建一个字段,修改原字段的所有用户,令他们改用新字段
某个类做了应该由两个类做的事。建立一个新类,将相关字段和函数从就类搬到新类。
某个类没有做太多的事情,不在承担足够责任,不再有的那单独存在的理由。将这个类的所有特性搬移到另一个类中,然后移除原类。
客户通过一个委托类来调用另一个对象。在服务类上建立客户所需要的所有函数,用来隐藏委托关系。封装意味每个对象都应该少了解系统的其他部分。一旦发生变化,需要了解这一变化的对象就会比较少。如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的函数。那么客户就必须知晓这一层委托关系。万一委托关系变化,客户也要相应变化。
某个类做了过多的简单委托。让客户直接调用委托类。每当客户要使用手委托类的新特性时,你就必须在服务端添加一个简单委托函数。随着受委托类的特性越来越多,这一过程会让你很痛苦。
你需要为提供服务的类增加一个函数,但你无法修改这个类。在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。
Date newStart = newDate(year, month, date + 1);替换为:
Date newStart = nextDay(nowDate); privatestaticDate nextDay(Date arg){ retrun newDate(arg.getYear(), arg.getMonth(), arg.getDate() + 1); }如果可以修改源码,你可以自行添加一个新函数;如果不能,你就得在客户端编码,补足你要的那个函数
你需要为服务类踢狗一些额外函数,但你无法修改这个类。建立一个新类,使它包含这些额外函数。让这个扩展品成为源类的子类或包装类。
直接访问一个字段。为这个字段建立取值/设值函数,并且只以这些函数来访问字段。
privateint low, high; boolean includes(int arg){ retrun arg >= low && arg <= high; }替换为:
privateint low, high; boolean includes(int arg){ retrun arg >= getLow() && arg <= getHigh(); } int getLow(){ retrun low; } int getHigh(){ return high; }在“字段访问方式”这个问题上,存在两种截然不同的观点:
在该变量定义所在的类中,你可以自由的访问。
即使在这个类中你也应该只使用访问函数间接访问。间接访问的好处是:子类可以通过复写一个函数而改变获取数据的途径;它支持更灵活的数据管理方式,例如延迟初始化。
你有一个数据项,需要与其他数据和行为一起使用才有意义。将数据项变为对象。一开始你肯能会用一个字符串来表示“电话号码”概念,但是随后你会发现,电话号码需要“格式化”、“区号”之类的行为。这时候就需要为带替换的数值新建一个类。
你从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象。将这个值对象变成引用对象。
你有一个引用对象,很小且不可改变,而且不易管理。将它变成一个值对象。
你有一个数组,其中的元素各自代表不同的东西。以对象替换数组。对于数组中的每个元素,以一个字段来表示
你有一些领域数据置身GUI控件中,而领域函数需要访问这些数据。将该数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。
两个类都需要使用对方特性,但其间只有一条单向连接。添加一个反向指针,并使修改函数能够同时更新两条连接。
两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。去除不必要的关联。
你有一个字面数值,带有特别含义。创造一个常量,根据其意义为它命名,并将上述的字面数值替换为常量。
你的类中存在一个public字段。将它声明为private,并提供相应的访问函数。
有个函数返回一个集合。让这个函数返回该集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。
有一复杂的条件语句。从if、then、else三个段落中分别提炼出独立函数。
你有一系列条件测试,都得到相同结果。将这些测试合并为一个条件表达式,并将这个条件表达式提炼成一个独立函数。
在表达式的每个分支上都执行了相同的一段代码。将这段重复代码搬移到条件表达式之外。
在一系列布尔表达式中,某个变量带有”控制标记”的作用。以break/return语句取代控制标记。
有个条件表达式根据对象类型的不同而选择不同的行为。将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数
函数的名称未能揭示其用途。修改函数名称。
某个函数需要从调用端得到更多信息。为此函数添加一个对象参数,让该对象带仅函数所需信息。
函数本体不再需要某个参数。去除参数。
某个函数既返回对象状态值,又修改对象值。建立两个不同函数,其中一个负责查询,另一个负责修改。
若干函数做了类似的工作,但在函数本体中包含了不同的值。建立单一函数,以参数表达那些不同的值。有这样两个函数:它们做着类似的工作,但因少数几个值致使行为略有不同。在这种情况下,你可以将这些各自分离的函数同一起来,并通过参数来处理那些变化情况,用以简化问题。
你有一个函数,其中完全取决于参数值而采用不同行为。针对该参数的每一个可能值,建立一个独立函数。如果某个参数有多种可能的值,而函数内又以条件表达式检查这些参数值,并根据不同参数值做出不同的行为,那么就应该使用本项重构。
从某个对象中取出若干值,将它们作为某一次函数调用时的参数。改为传递整个对象。
对象调用某个函数,并将所得结果作为参数,传递给另一函数,而接受该参数的函数本身也能够调用前一个函数。让参数接受者去除该参数,直接调用前一个函数。
某些参数总是很自然的同时出现。以一个对象取代这些参数。
类中某个字段在对象创建时被设值,然后不再改变。去掉该字段的所有设值函数。
某个函数,从来没有被其他任何类用到 。将函数修改为private。
希望在创建对象时不仅仅是做简单的建构动作 。将构造函数替换为工厂函数。
两个子类拥有相同的字段。将该字段移至超类。
有些函数在各子类中产生完全相同的结果。将该函数移至超类。
各个子类中有一些构造函数本体几乎完全一致 。在超类中新建一个构造函数,并在子类构造函数中调用它。
超类中的某个函数只与部分(而非全部)子类用到。将函数移到相关的子类中。
超类中的某个字段只被部分(而非全部)子类用到。将字段移到需要它的子类中。
类中的某些特性只被某些(而非全部)实例用到。新建一个子类,将上述部分的特性移到子类中。
两个类有相似特性。为这两个类建立一个超类,将相同特性移至超类。
若干客户使用类接口中的同一子集,或两个类的接口有部分相同。将相同的子集提炼到一个独立接口中。
超类和子类之间无太大区别。将它们合为一体。
子类中某些函数以相同顺序执行类似操作,但各操作细节略有不同。将操作放进独立函数(保持签名相同),然后将它们移至超类。
某个子类只使用超类接口中的一部分或根本不需要继承而来的数据。子类新建字段保存超类,调整子类函数为委托超类,取消继承关系。
作者:小村医 | https://url.cn/55vKv3X
看到这里啦,说明你对这篇文章感兴趣,帮忙转发一下或者点击文章右下角在看。感谢啦!关注公众号,回复「 进群 」即可进入 无广告技术交流群 。同时送上250本电子书+学习视频作为见面礼! 有你想看的 精彩