重构·改善既有代码的设计.03之重构手法(上)

Posted 有一只柴犬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重构·改善既有代码的设计.03之重构手法(上)相关的知识,希望对你有一定的参考价值。

1. 前言

之前的重构系列中,介绍了书中提到的重构基础,以及识别代码的坏味道。今天继续第三更,讲述那些重构手法(上)。看看哪些手法对你的项目能有所帮助…

2. 重新组织函数

对函数进行整理,使之更恰当的包装代码。

1、Extract Method 提炼函数。

改造前:

void printInfoAndDetail() 
     this.printInfo();   
     System.out.println("this is detail name:" + _name);
     System.out.println("this is detail account:" + _account);

改造后:

void printInfoAndDetail() 
     this.printInfo();   
     this.printDetail();


void printDetail()  
     System.out.println("this is detail name:" + _name);
     System.out.println("this is detail account:" + _account);

动机:
控制函数的粒度,函数粒度很小,那么被复用的机会就更大;其次会使高层函数读起来就像一系列注释,再次,如果函数都是细粒度,那么函数的覆盖也会更容易。
一个函数多长才算合适?其实长度不是关键问题,关键在于函数名和函数本体之间的语义距离。
做法:
1、创造一个新函数,根据这个函数意图来命名(以它”做什么“来命名,而不是”怎样做“命名)。
只要新的函数名能够以更好的方式昭示代码意图,你也应该提炼他(就算代码只是一条消息,或一个函数调用)。但如果你想不出一个更有意义的名称,就别动。
2、将提炼出来额代码从源函数复制到新建的目标函数中。
3、检查变量。检查提炼出的代码是否引用了源代函数的局部变量或参数。以被提炼函数中是否含有临时变量。
难点:
这个重构手法的难点就在于局部变量的控制,包括传进源函数的参数和源函数所有声明的临时变量。

2、Inline Method 内联函数。

改造前:

int getRating() 
     return isGe5() ? 2 : 1;


boolean isGe5()
    return _num >= 5;       

改造后:

int getRating() 
     return _num >= 5 ? 2 : 1;

动机:
移除非必要的间接层。当然间接层有其价值,但不是所有的间接层都有价值,可以去除那些无用的间接层。
做法:
1、检查函数,确定他不具备多态性。如果有子类继承了这个函数,那就不能将此函数内联。因为子类无法覆盖一个根本不存在的函数。如例子中,子类可以重写isGe5(),但内敛之后的_num > 5 ? 2 : 1是无法重写的,除非你重写了getRating()。
2、找出函数的所有被调用点,将这个函数的所有被调用点都替换为函数本体。

3、Inline Temp 内联临时变量。

改造前:

double price = order.price();
return price > 1000;

改造后:

return order.price() > 1000

4、Replace Temp With Query 以查询取代临时变量。

改造前:

double price = _qu * _item;
if(price > 1000)
    return price * 0.95;
 else 
    return price * 0.98;   

改造后:

if(getPrice() > 1000)
    return getPrice() * 0.95;
 else 
    return getPrice() * 0.98;   


double getPrice()
    return _qu * _item;

5、Introduce Explaining Variable 引入解释性变量。

改造前:

if((platform.indexOf("mac") > -1) 
   && (platform.indexOf("ie") > -1) 
   && resize > 0
)
 // todo...        

改造后:

final boolean isMac = (platform.indexOf("mac") > -1;
final boolean isIe = (platform.indexOf("ie") > -1;
final boolean resized = resize > 0;

if( && isIe && resized)
  // todo...        

6、Split Temporary Variable 分解临时变量。

改造前:

double temp = 2 * (_h + _w);
System.out.println(temp);
temp = _h * _w;
System.out.println(temp);

改造后:

final double temp = 2 * (_h + _w);
System.out.println(temp);
final double area = _h * _w;
System.out.println(area);

7、Remove Assignments to Parameters 移除对参数的赋值。

改造前:

int discount(int inputVal) 
    if(inputVal > 50) inputVal -= 2;

改造后:

int discount(int inputVal) 
    int result = inputVal;
    if(inputVal > 50) result -= 2;

3. 在对象之间搬移特性

“决定把责任放在哪儿”。

1、Move Method 搬移函数。

如果一个类有太多的行为,或如果一个类于另一个类有太多合作而形成高度耦合,尝试搬移函数。将旧函数变成一个单纯的委托函数,或是将旧函数完全移除。
改造前:

class Account 
    private AccountType _type;
    private int _dayOverdrawn;
    
    double overdraftCharge()
        if(_type.isPremium()) 
            double result = 10;
            if(_dayOverdrawn > 7) result += (_dayOverdrawn - 7) * 0.85;
            return result;        
         else 
            return _dayOverdrawn * 1.75;        
        
    

改造后:

class Account 
    private AccountType _type;
    private int _dayOverdrawn;
    
    double overdraftCharge()
        return _type.overdraftCharge(_dayOverdrawn);
    



class AccountType 
    double overdraftCharge(int daysOverdrawn)
        if(isPremium()) 
            double result = 10;
            if(dayOverdrawn > 7) result += (dayOverdrawn - 7) * 0.85;
            return result;        
         else 
            return dayOverdrawn * 1.75;        
        
    

2、Move Field 搬移字段。

如果一个字段,在其所驻类之外的另一个类中有更多函数使用了它,就要考虑搬移这个字段。这里的使用可能是设值,取值函数间接进行的。
改造前:

class Account 
    private AccountType _type;
    private int _rate;
    
    double overdraftCharge(double amount, int days)
        return _rate * amount * days / 365;
    

改造后:

class Account 
    private AccountType _type;
    
    double overdraftCharge()
        return _type.getRate() * amount * days / 365;
    



class AccountType 
    private double _rate;
    void setRate(double r) 
        this._rate = r;    
    
    void getRate() 
        return _rate;  
    

3、Extract Class 提炼类。

建立一个新类,将相关的字段和函数从旧类搬移到新类。一个类应该是一个清楚的抽象,处理一些明确的责任。
改造前:

class Account 
    private String personName;
    private String personPhone;
    private double money;
    
    public String getAccountInfo()
        return personName + ",联系方式:" + personPhone + ",余额:" + money;    
        

改造后:

class Account 
    private Person person = new Person();
    private double money;
    
    public String getAccountInfo()
        return person.getPersonName() + person.personPhone() + ",余额:" + money;    
        


class Person 
    private String personName;
    private String personPhone;
    
    public String getPersonName()
        return "联系人:" + personName;
    
    public String getPersonPhone()
        return "联系方式:" + personPhone;
    

4、Inline Class 将类内联化。

将这个类的所有特性搬移到另一个类中,然后移除原类。与Extract Class相反。

5、Hide Delegate 隐藏“委托关系”。

“封装”即使不是对象的最关键特性,也是最关键特性之一。“封装”意味着每个对象都应该尽可能少了解系统的其他部分。
改造前:

class Person 
    private Department department;
    
    public Department getDepartment()
        return department;
        


class Department 
    private Person manager;
    
    public Person getManager()
        return manager;    
    


// 如果客户希望知道某人的经理是谁,那他的调用关系是:
xxx.getDepartment().getManager();
// 暴露了部门和经理的委托关系

改造后:

class Person 
    private Department department;
    
    public Department getDepartment()
        return department;
    
    
    public Person getManager()
        return department.getManager();    
        


class Department 
    private Person manager;
    
    public Person getManager()
        return manager;    
    


// 如果客户希望知道某人的经理是谁,那他的调用关系是:(隐藏了Department)
xxx.getManager();

6、Remove Middle Man 移除中间人。

某个类做了过多的简单委托动作。

7、Introduce Foreign Method 引入外加函数。

当你需要为提供服务的类增加一个函数,但你无法修改这个类。如果你只使用这个函数一次,那么额外编码工作没什么大不了,升值可能根本不需要原本提供服务的那个类。然而,如果你需要多次使用这个函数,就得不断重复这些代码。重复代码是软件万恶之源。
改造前:

Date newStart = new Date(pre.getYear(), pre.getMethod(), pre.getDate() + 1);

改造后:

Date newStart = nextDay(pre);

private static Date nextDay(Date arg) 
    return new Date(arg.getYear(), arg.getMethod(), arg.getDate() + 1);

如真实项目中的案例:
BeanUtil.copyProperties(),原始方法该行为需要抛异常,且被建议不再使用该方法进行bean复制。
于是引入外加函数:

class BeanUtilExt 
    public static void copyProperties(Object target, Object source) 
        try 
              BeanUtil.copyProperties()      
         catch (Exception) 
            // ignored...        
            
    

这种方式个人不推荐。

8、Introduce Local Extension 引入本地扩展。

当你需要为提供服务的类提供一些额外函数,但你无法修改这个类。

4. 重新组织数据

1、Self Encapsulate Field 自封装字段。

改造前:

private int _low, _high;
boolean includes(int arg)
    return arg >= _low && arg <= _high;

改造后:

private int _low, _high;
boolean includes(int arg)
    return arg >= getLow() && arg <= getHigh();


int getLow()
    return _low;

int getHigh()
    return _high;

直接访问变量好处:代码容易阅读。
间接访问变量好处:子类可以通过重写(覆盖)一个函数而改变获取数据的途径。

2、Replace Data Value with Object 以对象取代数据值。

开发初期,你往往决定以简单的数据项表示简单的情况。但是,随着开发的进行,你可能会发现,这些简单的数据项不再那么简单了。比如你一开始会用字符串来表示“电话号码”,但是随后你会发现,电话号需要“格式化”,“抽取区号”之类的特殊行为。如果这样的数据项只有一两个,你还可以把相关函数放进数据项所属的对象里,但是Duplicate Code和Feature Envy很快就会表现出来。这时,你就应该将数值变为对象。

3、Change Value toReference 将值对象改为引用对象。

你从一个类衍生出许多批次相等的实例,希望将它们替换为同一个对象。

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

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

5、Replace Array with Object 以对象取代数组。

你有一个数组,其中的元素各自代表不同的东西。
改造前:

String[] row = new String[3];
row[0] = "liver";
row[1] = "15";

改造后:

Performance row = new Performance();
row.setName("liver");
row.setWins(15);

6、Duplicate Observed Data 复制“被监视数据”。

有一些领域数据置身于GUI组件中,而领域函数需要访问这些数据。
将该数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。可以使用事件监听器,诸如JAVAFX中的Property。

7、Change Unidirectional Association to Bidirectional 将单向关联改为双向关联。

两个类都需要使用对方特性,但其间只有一条单向链接。

8、Change Bidirectional Association to Unidirectional 将双向关联改为单向关联。

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

9、Replace Magic Number with Symbolic Constant 以字面常量取代魔法值。

改造前:

double count(double a, double b)
    return a * 0.95 * b;

改造后:

double count(double a, double b)
    return a * RATE_CONSTANT * b;

static final double RATE_CONSTANT = 0.95;

10、Encapsulate Field 封装字段。

即面向对象的首要原则之一:封装,或称为“数据隐藏”。
改造前:

public String _name;

改造后:

private String _name;

public String getName() 
    return _name;


public void setName(String name) 
    this._name = name;

11、Encapsulate Collection 封装集合。

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

class Person 
    List<String> classes;
    
    public List<String> getClasses()
        return classes;   
    
    
    public void setClasses(List<String> cls)
        this.classes = cls;
    

改造后:

class Person 
    List<String> classes;
    
    public List<String> getClasses()
        return classes;   
    
    
    // setter方法隐藏,避免用户修改集合内容而一无所知
    private void setClasses(List<String> cls)
        this.classes = cls;
    
    
    public void addClass(String cls) 
        classes.add(cls);
    
    
    public void removeClass(String cls) 
        classes.remove(cls);
    

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

主要用来应对传统编程环境中的记录结构。

13、Replace Type Code with Class 以类取代类型码。

类中有一个数值类型码,但它并不影响类的行为。
改造前:

class Person 
    public static final int O = 0;
    public static final int A = 1;
    public static final int B = 2;
    public static final int AB = 3;
    
    @Getter
    @Setter
    private int _bloodGroup;
    
    public Person(int bloodGroup) 
         _bloodGroup = bloodGroup;
    

改造后:

class Person 
    public static final int O = BloodGroup.O.getCode();
    public static final int A = BloodGroup.A.getCode();
    public static final int B = BloodGroup.B.getCode();
    public static final int AB = BloodGroup.AB.getCode();
    
    @Getter
    private int _bloodGroup;
    
    public Person(int bloodGroup) 
         _bloodGroup = BloodGroup.code(bloodGroup);
    
    
    public void setBloodGroup(int arg) 
         _bloodGroup = BloodGroup.code(arg)1. 前言 

本文是代码重构系列的最后一篇啦。前面三篇《重构·改善既有代码的设计.01之入门基础》、《重构·改善既有代码的设计.02之代码的“坏味道”》、《重构·改善既有代码的设计.03之重构手法(上)》介绍了基础入门,代码异味,还有部分重构手法。今天继续总结重构手法下篇,从条件表达式、函数调用、以及类继承关系上阐述了各种重构手法,希望对项目能有所帮助。另外本文更新后该系列就完结了,感谢各位看官的指点。

2. 简化条件表达式

“分支逻辑”和“操作细节”分离。

1、Decompose Conditional 分解条件表达式。

复杂的条件语句(if-then-else)。
改造前:

if(date.before(SUMMER_START) || date.after(SUMMER_END)) 
    charge = quantity * _winterRate * _winterServiceCharge;
 else 
    charge = quantity * _summerRate;

改造后:

if(notSummer(date)) 
    charge = winterCharge(quantity);
 else 
    charge = summerCharge(quantity);


private boolean notSummer(Date date) 
    return date.before(SUMMER_START) || date.after(SUMMER_END);


private double summerCharge(int quantity) 
    return quantity * _summerRate;


private double winterCharge(int quantity) 
    return quantity * _winterRate * _winterServiceCharge;

2、Consolidate Conditional Expression 合并条件表达式。

有一系列条件测试,都得到相同结果。将这些测试合并为一个条件表达式,并将这个条件表达式提炼成一个独立函数。
改造前:

double disabilityAmount()
    if(_seniority < 2) 
        return 0;    
    
    if(_monthDisabled > 12) 
        return 0;    
    
    if(_isPartTime) 
        return 0;    
    
    // todo...

改造后:

double disabilityAmount()
    if((_seniority < 2) || (_monthDisabled > 12) || _isPartTime) 
        return 0;    
    
    // todo...


或:
double disabilityAmount()
    if(isDisability()) 
        return 0;    
    
    // todo...


boolean isDisability() 
    return (_seniority < 2) || (_monthDisabled > 12) || _isPartTime;

3、Consolidate Duplicate Conditional Fragments 合并重复的条件片段。

条件表达式的每个分支上有着相同的一段代码。
改造前:

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();

4、Remove Control Flag 移除控制标记。

循环体中,通常需要判断何时停止条件检查。有时会引入某个控制变量来起到循环判断的作用。建议以break或continue或return 语句取代控制标记。
改造前:

void check(String[] person) 
    boolean found = false;   // 控制标记
    for(int i = 0; i < person.length; i++) 
        if(!found) 
            if(person[i] == "tom") 
                found = true;
                sendAlert();                
            
            if(person[i] == "jose") 
                found = true;
                sendAlert();                
                      
            
    
    

改造后:

void check(String[] person) 
    boolean found = false;   // 控制标记
    for(int i = 0; i < person.length; i++) 
        if(!found) 
            if(person[i] == "tom") 
                sendAlert();
                break;                
            
            if(person[i] == "jose") 
                sendAlert();    
                break;            
                      
            
    
    

5、Replace Nested Conditional with Guard Clauses 以卫语句取代嵌套条件表达式。

条件表达式中,如果两条分支都是正常行为,使用形如if…else…的条件表达式;如果某个条件极为罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回(如参数校验判断)。这样的单检查称为“卫语句”。
卫语句要么就从函数中返回,要么就抛出一个异常。
改造前:

double getPayment()
    double result;
    if(_isDead) 
        result = deadAmount();    
     else 
        if(_isSeparated) 
            result = separatedAmount();        
         else 
            if(_isRetired) 
                result = retiredAmount();            
             else 
                result = normalAmount();            
                   
            
    
    
    return result;

改造后:

double getPayment()
    if(_isDead) 
        return deadAmount();    
    
    if(_isSeparated) 
       return separatedAmount();        
    
    if(_isRetired) 
       return retiredAmount();    
            
        
    return normalAmount(); 

6、Replace Conditional with Polymorphism 以多态取代条件表达式。

改造前:

class Employee 
    private EmployeeType _type;
    
    int payment() 
        switch(getType()) 
            case EmployeeType.ENGINEER:
                return _monthlySalary;
            case EmployeeType.SALESMAN:
                return _monthlySalary + _commission;
            case EmployeeType.MANAGER:
                return _monthlySalary + _bonus;
            default:
                throw new RuntimeException("error");                                                    
            
    
    
    int getType() 
        return _type.getTypeCode();    
    


abstract class EmployeeType 
    abstract int getTypeCode();


class Engineer extends EmployeeType 
    int getTypeCode()
        return EmployeeType.ENGINEER;    
    


class Salesman extends EmployeeType 
    int getTypeCode()
        return EmployeeType.SALESMAN;    
    


class Manager extends EmployeeType 
    int getTypeCode()
        return EmployeeType.MANAGER;    
    

改造后:

class Employee 
    private EmployeeType _type;
    
    int payment() 
        return _type.payment();  
    


abstract class EmployeeType 
    abstract int payment(Employee emp);


class Engineer extends EmployeeType 
    int payment(Employee emp)
        return emp.getMonthlySalary();   
    


class Salesman extends EmployeeType 
    int payment(Employee emp)
        return emp.getMonthlySalary() + emp.getCommission();   
    


class Manager extends EmployeeType 
    int payment(Employee emp)
        return emp.getMonthlySalary() + emp.getBonus();   
    

7、Introduce Null Object 引入Null对象。

将null替换为null对象。
改造前:

class Site 
    private Customer _customer;
    Customer getCustomer() 
        return _customer;    
    


class Customer 
    public Stirng getName() ...
    public BillingPlan getPlan()...


// 调用
Customer customer = site.getCustomer();
if(customer == null) 
    plan = BillingPlan.basic();
 else 
    plan = customer.getPlan();

String customerName;
if(customer == null) 
    customerName = "default";
 else 
    customerName = customer.getName();

改造后:

class Site 
    private Customer _customer;
    Customer getCustomer() 
        return _customer == ull ? Customer.newNull() : _customer;   
    


class Customer 
    public Stirng getName() ...
    public BillingPlan getPlan()...
    
    public boolean isNull() 
        return false;    
    
    
    static Customer newNull() 
        return new NullCustomer();    
    


// 定义NullCustomer空对象
class NullCustomer extends Customer
    public boolean isNull() 
        return true;    
    


// 调用
Customer customer = site.getCustomer();
if(customer.isNull()) 
    plan = BillingPlan.basic();
 else 
    plan = customer.getPlan();

String customerName;
if(customer.isNull()) 
    customerName = "default";
 else 
    customerName = customer.getName();

8、Introduce Assertion 引入断言。

一段代码需要对程序状态做出某种假设。以断言明确表现这种假设。
改造前:

double getExpenseLimit() 
    return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit : _primaryProject.getMemberExpenseLimit();

改造后:

double getExpenseLimit() 
    Assert.isTrue(_expenseLimit != NULL_EXPENSE || _primaryProject != null);
    return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit : _primaryProject.getMemberExpenseLimit();

断言,请不要用它来检查“你认为应该为真”的条件,请只使用它来检查“一定必须为真”的条件。请勿滥用。
如果断言所指示的约束条件不能满足,代码是否仍能正常运行? 如果可以,就把断言去掉。

3. 简化函数调用

容易被理解和被使用的接口,是开发良好面向对象软件的关键。

1、Rename Method 函数改名。

将复杂的处理过程分解成小函数。但是如果做的不好,会使你费尽周折却弄不清楚这些小函数各自的用途。要避免这种麻烦,关键在于给函数起一个好名称。
1、尽可能起一个良好名称的函数,顾名思义表达该函数的作用,而不是表达该函数如何做。
2、合理安排函数签名,如果重新安排参数顺序,能够帮助提供代码的清晰度。

2、Add Parameter 添加参数。

为函数添加一个对象参数,让该对象带进函数所需信息。
动机:
你必须修改一个函数,而修改后的函数需要一些过去没有的信息,因此你需要给该函数添加一个参数。
改造前:

double getExpenseLimit(double limit) 
    // todo...


// 需要添加一个参数
double getExpenseLimit(double limit, Date date) 
    // todo...

改造后:

double getExpenseLimit(ExpenseLimit limitObj) 
    // todo...
    double limit = limitObj.getLimit();
    Date date = limitObj.getDate();


class ExpenseLimit 
    double limit;
    Date date;

但是需要警惕引用传递。其实我并不推荐整个对象传参。当你传整个参数时,对于这个函数你不能准确的说出这个函数所使用的参数。有可能对象包含了5个参数,而你理论上只需要3个。 这时候宁可将参数依次卸载参数列表中。不过所带来的影响是代码参数过长。如果过长,也是不太友好的。
推荐:适当使用参数列表和对象参数,必要时可以进行函数重载更简洁说明函数意图。比如:

double getExpenseLimit(double limit) 
    this.getExpenseLimit(limit, new Date());


double getExpenseLimit(double limit, Date date) 
    ExpenseLimit limitObj = new ExpenseLimit(limit, date);
    this.getExpenseLimit(limitObj);


double getExpenseLimit(ExpenseLimit limitObj) 
    // todo...
    double limit = limitObj.getLimit();
    Date date = limitObj.getDate();


class ExpenseLimit 
    double limit;
    Date date;

3、Remove Parameter 移除参数。

移除函数体无用参数。
改造前:

double getExpenseLimit(double limit, Date date) 
    return limit * 0.98;

改造后:

double getExpenseLimit(double limit) 
    return limit * 0.98;

4、Separate Query from Modifier 将查询函数和修改函数分离。

某个函数既返回对象状态值,又修改对象状态。

5、Parameterize Method 令函数携带参数。

若干函数做了类似的工作,但在函数本体中却包含了不同的值。
改造前:

class Employee 
    void tenPercentRaise() 
        salary *= 1.1;    
    
    void fivePercentRaise() 
        salary *= 1.05;    
    

改造后:

class Employee 
    void raise(double factor) 
        salary *= (1 + factor);    
    

6、Replace Parameter with Explicit Methods 以明确函数取代参数。

有一个函数,其中完全取决于参数值而采取不同行动。
改造前:

void setValue(String name, int value) 
    if(name.equals("height")) 
        _height = value;
        return ;    
    
    if(name.equals("width")) 
        _width = value;
        return ;    
    

改造后:

void setHeight(int value) 
    _height = value;

void setWidth(int value) 
    _width = value;

7、Preserve Whole Object 保持对象完整。

从某个对象中取出若干值,将它们作为某一个函数调用时的参数。
改造前:

int low = daysTempRange().getLow();
int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);

改造后:

withinPlan = plan.withinRange(daysTempRange());

注:
该方法总有两面。如果你传的是数值,被调用函数就只依赖于这些数值,而不依赖它们所属的对象。但如果你传递的是整个对象,被调用函数所在的对象就需要依赖参数对象。如果这样,会使你的依赖结构恶化,那么就不该使用该方法。

8、Replace Parameter with Methods 以函数取代参数。

对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。
改造前:

int basePrice = _quantity * _itemPrice;
discountLevel = getDiscountLevel();
double finalPrice = discountedPrice(basePrice, discountLevel);

改造后:

int basePrice = _quantity * _itemPrice;
double finalPrice = discountedPrice(basePrice);

double discountedPrice(int basePrice) 
    discountLevel = getDiscountLe

以上是关于重构·改善既有代码的设计.03之重构手法(上)的主要内容,如果未能解决你的问题,请参考以下文章

重构改善既有代码设计--重构手法 之重新组织你的函数总结

重构:改善既有代码的设计读书笔记——开篇

重构改善既有代码设计--重构手法02:Inline Method (内联函数)& 03: Inline Temp(内联临时变量)

重构改善既有代码设计--重构手法14:Hide Delegate (隐藏委托关系)

重构改善既有代码设计--重构手法01:Extract Method (提炼函数)

重构改善既有代码设计--重构手法09:Substitute Algorithm (替换算法)

(c)2006-2024 SYSTEM All Rights Reserved IT常识