代码重构—函数重构
1.提取函数
提取函数是将一段代码提取成函数,这样可以避免重复代码和函数过长
提取前:
void printOwing() {
printBanner();
//print details
System.out.println("name: " + name);
System.out.println("amount: " + getOutstanding());
}
提取后:
void printOwing() {
printBanner();
printDetails();
}
2.提取变量
当我们有一个较长或较复杂的表达式时,我们可以将其提取为变量
提取前:
void renderBanner() {
if ((platform.toUpperCase().indexOf("MAC") > -1) &&
(browser.toUpperCase().indexOf("IE") > -1) &&
wasInitialized() && resize > 0 )
{
// do something
}
}
提取后:
void renderBanner() {
final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIE = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;
if (isMacOs && isIE && wasInitialized() && wasResized) {
// do something
}
}
3.合并条件表达式
当有多个条件导致相同的结果或操作时,可以将其合并为一个表达条件的函数
合并前:
double disabilityAmount() {
if (seniority < 2) {
return 0;
}
if (monthsDisabled > 12) {
return 0;
}
if (isPartTime) {
return 0;
}
// compute the disability amount
//...
}
合并后:
double disabilityAmount() {
if (isNotEligableForDisability()) {
return 0;
}
// compute the disability amount
//...
}
4.合并重复的条件片段
当不同的条件中有相同代码时,可以将相同的代码提取到条件外
合并前:
if (isSpecialDeal()) {
total = price * 0.95;
send();
}
else {
total = price * 0.98;
send();
}
合并后:
if (isSpecialDeal()) {
total = price * 0.95;
}
else {
total = price * 0.98;
}
send();
5.分解条件
复杂的条件(if-then/ else或switch)应该分解
分解前:
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
}
else {
charge = quantity * summerRate;
}
分解后:
if (isSummer(date)) {
charge = summerCharge(quantity);
}
else {
charge = winterCharge(quantity);
}
6.分解多层嵌套
当嵌套过多时,逻辑会变得非常复杂,嵌套最好不要超过3层
分解前:
public double getPayAmount() {
double result;
if (isDead){
result = deadAmount();
}
else {
if (isSeparated){
result = separatedAmount();
}
else {
if (isRetired){
result = retiredAmount();
}
else{
result = normalPayAmount();
}
}
}
return result;
}
分解后:
public double getPayAmount() {
if (isDead){
return deadAmount();
}
if (isSeparated){
return separatedAmount();
}
if (isRetired){
return retiredAmount();
}
return normalPayAmount();
}
7.分解条件
复杂的条件(if-then/ else或switch)应该分解
分解前:
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
}
else {
charge = quantity * summerRate;
}
分解后:
if (isSummer(date)) {
charge = summerCharge(quantity);
}
else {
charge = winterCharge(quantity);
}
8.内联临时变量
如果可以用表达式本身替换变量,就没有必要再用临时变量
内联前:
boolean hasDiscount(Order order) {
double basePrice = order.basePrice();
return basePrice > 1000;
}
内联后:
boolean hasDiscount(Order order) {
return order.basePrice() > 1000;
}
9.内联函数
如果函数本色能表达其意思,就没有必要再用临时变量进行转换
内联前:
class PizzaDelivery {
//...
int getRating() {
return moreThanFiveLateDeliveries() ? 2 : 1;
}
boolean moreThanFiveLateDeliveries() {
return numberOfLateDeliveries > 5;
}
}
内联后:
class PizzaDelivery {
//...
int getRating() {
return numberOfLateDeliveries > 5 ? 2 : 1;
}
}
10.用函数替换临时变量
将表达式移动到单独的函数中,而不是使用变量去保存,以便其他地方可以调用。
替换前:
double calculateTotal() {
double basePrice = quantity * itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
}
else {
return basePrice * 0.98;
}
}
替换后:
double calculateTotal() {
if (basePrice() > 1000) {
return basePrice() * 0.95;
}
else {
return basePrice() * 0.98;
}
}
double basePrice() {
return quantity * itemPrice;
}
11.拆分临时变量
对不同的值使用不同的变量,每个变量应该只做一件事。
拆分前:
double temp = 2 * (height + width);
System.out.println(temp);
temp = height * width;
System.out.println(temp);
拆分后:
final double perimeter = 2 * (height + width);
System.out.println(perimeter);
final double area = height * width;
System.out.println(area);
12.用对象替换函数
将函数转换为单独的类,以便局部变量成为类的字段,然后,您可以将方法拆分为同一个类中的多个函数。
替换前:
class Order {
//...
public double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation.
//...
}
}
替换后:
class Order {
//...
public double price() {
return new PriceCalculator(this).compute();
}
}
class PriceCalculator {
private double primaryBasePrice;
private double secondaryBasePrice;
private double tertiaryBasePrice;
public PriceCalculator(Order order) {
// copy relevant information from order object.
//...
}
public double compute() {
// long computation.
//...
}
}
13.替代算法
对不同的值使用不同的变量,每个变量应该只做一件事。
替代前:
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(new String[] {"Don", "John", "Kent"});
for (int i=0; i < people.length; i++) {
if (candidates.contains(people[i])) {
return people[i];
}
}
return "";
}
14.用函数替换参数
将函数的各个部分提取到自己的函数中,然后调用它们而不是原始函数
替代前:
void setValue(String name, int value) {
if (name.equals("height")) {
height = value;
return;
}
if (name.equals("width")) {
width = value;
return;
}
}
替换后:
void setHeight(int arg) {
height = arg;
}
void setWidth(int arg) {
width = arg;
}
15.用异常替换错误代码
替代前:
int withdraw(int amount) {
if (amount > _balance) {
return -1;
}
else {
balance -= amount;
return 0;
}
}
替换后:
void withdraw(int amount) throws BalanceException {
if (amount > _balance) {
throw new BalanceException();
}
balance -= amount;
}
15.用测试替换异常
替代前:
double getValueForPeriod(int periodNumber) {
try {
return values[periodNumber];
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
}
替换后:
double getValueForPeriod(int periodNumber) {
if (periodNumber >= values.length) {
return 0;
}
return values[periodNumber];
}