重构-改善既有代码的设计完整笔记系列之10、11 - 简化函数、处理概括关系

10.1 Rename Method(函数改名)

  • 10.2 Add Parameter(添加参数)
  • 10.3 Remove Parameter(移除参数)
  • 10.4 Separate Query from Modifier(将查询函数和修改函数分离)
  • 10.5 Parameterize Method(令函数携带参数)
  • 10.6 Replace Parameter with Explicit Methods(以明确函数取代参数)
  • 10.7 Preserve Whole Object(保持对象完整)
  • 10.8 Replace Parameter with Methods(以函数取代参数)
  • 10.9 Introduce Parameter Object(引入参数对象)
  • 10.10 Remove Setting Method(移除设值函数)
  • 10.11 Hide Method(隐藏函数)
  • 10.12 Replace Constructor with Factory Method(以工厂函数取代构造函数)
  • 10.13 Encapsulate Downcast(封装向下转型)
  • 10.14 Replace Error Code with Exception(以异常取代错误码)
  • 10.15 Replace Exception with Test(以测试取代异常)
  • 11.1 Pull Up Field(字段上移)
  • 11.2 Pull Up Method(函数上移)
  • 11.3 Pull Up Constructor Body(构造函数本体上移)
  • 11.4 Push Down Method(函数下移)
  • 11.5 Push Down Field(字段下移)
  • 11.6 Extract Subclass(提炼子类)
  • 11.7 Extract Superclass(提炼超类)
  • 11.8 Extract Interface(提炼接口)
  • 11.9 Collapse Hierarchy(折叠继承体系)
  • 11.10 Form Tem Plate Method(塑造模板函数
  • 11.11 Replace Inheritance with Delegation(以委托取代继承)
  • 11.12 Replace Delegation with Inheritance(以继承取代委托)


10.1 Rename Method(函数改名)
10.2 Add Parameter(添加参数)
10.3 Remove Parameter(移除参数)
10.4 Separate Query from Modifier(将查询函数和修改函数分离)
略

10.5 Parameterize Method(令函数携带参数)

若干函数做了类似的工作,但在函数本体中却包含了不同的值。
建立一个单一函数,以参数表达那些不同的值。
类似函数提取

    protected Dollars baseCharge() {
        double result = Math.min(lastUsage(), 100) * 0.03;
        if (lastUsage() > 100) {
            result += (Math.min(lastUsage(), 200) - 100) * 0.05;
        }
        if (lastUsage() > 200) {
            result += (lastUsage() - 200) * 0.07;
        }
        return new Dollars(result);
    }
//替换为
    protected Dollars baseCharge() {
        double result = usageInRange(0, 100) * 0.03;
        result += usageInRange(100, 200) * 0.05;
        result += usageInRange(200, Integer.MAX_VALUE) * 0.07;
        return new Dollars(result);
    }

    protected int usageInRange(int start, int end) {
        if (lastUsage() > start)
            return Math.min(lastUsage(), end) - start;
        else
            return 0;
    }

10.6 Replace Parameter with Explicit Methods(以明确函数取代参数)

某个函数完全取决于参数值而采取不同行为,为了获得一个清晰的接口,
针对该参数的每一个可能值,建立一个独立函数。

    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER = 2;

    static Employee create(int type) {
        switch (type) {
        case ENGINEER:
            return new Engineer();
        case SALESMAN:
            return new Salesman();
        case MANAGER:
            return new Manager();
        default:
            throw new IllegalArgumentException("Incorrect type code    value");
        }
    }
//打散为独立函数:
    static Employee createEngineer() {
        return new Engineer();
    }

    static Employee createSalesman() {
        return new Salesman();
    }

    static Employee createManager() {
        return new Manager();
    }

10.7 Preserve Whole Object(保持对象完整)

如果从对象中取出若干值,将它们作为某一次函数调用时的参数。改为传递整个对象。
除了可以使参数列更稳固外,还能简化参数列表,提高代码的可读性。
此外,使用完整对象,被调用函数可以利用完整对象中的函数来计算某些中间值。

int low = daysTempRange().getLow();
int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);
//替换:
withinPlan = plan.withinRange(daysTempRange());

10.8 Replace Parameter with Methods(以函数取代参数)

对象调用某个函数,并将所得结果作为参数,传递给另一个函数。
而接受该参数的函数本身也能够调用前一个函数。
让参数接受者去除该项参数,并直接调用前一个函数。

    public double getPrice() {
        int basePrice = _quantity * _itemPrice;
        int discountLevel;
        if (_quantity > 100)
            discountLevel = 2;
        else
            discountLevel = 1;
        double finalPrice = discountedPrice(basePrice, discountLevel);
        return finalPrice;
    }

    private double discountedPrice(int basePrice, int discountLevel) {
        if (discountLevel == 2)
            return basePrice * 0.1;
        else
            return basePrice * 0.05;
    }
//看出2个方法里的2个重复的discountLevel判断了吗?我们可以减少一个discountLevel参数,增加一个函数,让条理更清晰。
    private double getPrice() {
        if (getDiscountLevel() == 2)
            return getBasePrice() * 0.1;
        else
            return getBasePrice() * 0.05;
    }

    private int getDiscountLevel() {
        if (_quantity > 100)
            return 2;
        else
            return 1;
    }
    
    private double getBasePrice() {
        return _quantity * _itemPrice;
    }
//以上是原书的例子,我认为0.1和0.05这种数值出现的有点别扭,其实还是可以这么改:
    private double getPrice() {
        double finalPrice = getDiscountPrice(getBasePrice());
        return finalPrice;
    }

    private double getDiscountPrice(double basePrice) {
        if (_quantity > 100)
            return getBasePrice() * 0.1;
        else
            return getBasePrice() * 0.05;
    }
    
    private double getBasePrice() {
        return _quantity * _itemPrice;
    }
//是不是逻辑更清楚了?

 

10.9 Introduce Parameter Object(引入参数对象)
如果一组参数总是一起被传递,以一个对象取代这些参数


10.10 Remove Setting Method(移除设值函数)

    class Account {
        private String _id;

        Account(String id) {
            setId(id);
        }

        void setId(String arg) {
            _id = arg;
        }
    }
//可以这么改,禁止设置ID
    class Account {
        private final String _id;

        Account(String id) {
            _id = id;
        }
    }
//设置ID
    class Account {
        private String id;
        Account(String id) {
            setId(id);
        }

        private void setId(String arg) {
            id = "aaa" + arg;
        }
    }

10.11 Hide Method(隐藏函数)


10.12 Replace Constructor with Factory Method(以工厂函数取代构造函数)

这个和上一章的不变对象的例子相似。

class Person...
static Person createMale(){
    return new Male();
}
static Person createFemale() {
    return new Female();
}

Person kent = new Male();
//替换
Person kent = Person.createMale();

 

10.13 Encapsulate Downcast(封装向下转型)
10.14 Replace Error Code with Exception(以异常取代错误码)
10.15 Replace Exception with Test(以测试取代异常)
11.1 Pull Up Field(字段上移)
11.2 Pull Up Method(函数上移)
略


11.3 Pull Up Constructor Body(构造函数本体上移)
各个子类中拥有一些构造函数,它们的本体几乎完全一致。
在超类中新建一个构造函数,并在子类构造函数中调用它。

class Manager extends Employee...
public Manager (String name, String id, int grade) {
    _name = name;
    _id = id;
    _grade = grade;
}

//替换为
public Manager (String name, String id, int grade) {
    super (name, id);
    _grade = grade;
}
//由Employee完成部分构造

 

11.4 Push Down Method(函数下移)
11.5 Push Down Field(字段下移)
略

11.6 Extract Subclass(提炼子类)

类中的某些特性只被某些实例用到。新建一个子类,将这部分特性移到子类中

class JobItem {
    private int _unitPrice;
    private int _quantity;
    private Employee _employee;
    private boolean _isLabor;

    public JobItem(int unitPrice, int quantity, boolean isLabor, Employee employee) {
        _unitPrice = unitPrice;
        _quantity = quantity;
        _isLabor = isLabor;
        _employee = employee;
    }

    public int getTotalPrice() {
        return getUnitPrice() * _quantity;
    }

    public int getUnitPrice() {
        return (_isLabor) ? _employee.getRate() : _unitPrice;
    }

    public int getQuantity() {
        return _quantity;
    }

    public Employee getEmployee() {
        return _employee;
    }


}

class Employee {
    public Employee(int rate) {
        _rate = rate;
    }

    public int getRate() {
        return _rate;
    }

    private int _rate;
}

//使用JobItem来对雇员结算报酬,如果是计时体力活(_isLabor),那么单价(getUnitPrice())就在Employee中设置价格,否则就用_unitPrice。
//其实以上代码比较短,看起来没问题
//目前是只有一个类型参数true:
JobItem j1 = new JobItem (0, 5, true, kent);
//如果条件逻辑再多七八个,那就容易乱了。
//我们增加JobItem一个构造函数
public JobItem (int unitPrice, int quantity) {
    this (unitPrice, quantity, false, null)
}
//这样就可以直接调用
JobItem j2 = new JobItem (10, 15);
//注意,这个j2实例不是计时体力活
//增加一个子类
class LaborItem
public LaborItem (int quantity, Employee employee) {
    super (0, quantity, true, employee);
}

 

11.7 Extract Superclass(提炼超类)
两个类有相似特性。为这2个类建立一个超类,将相同特性移至超类。
避免重复代码。
11.8 Extract Interface(提炼接口)
面向接口编程,大部分的设计模式都需要它。

11.9 Collapse Hierarchy(折叠继承体系)
也即取消一些多余的子类

11.10 Form Tem Plate Method(塑造模板函数)
一些子类,其中相应的某些函数以相同的顺序执行类似的操作,但各个操作的细节不同。
将这些操作分别放迚独立的函数中,并保持它们都有相同的签名,于是原函数也就变得相同了,然后将原函数上移至超类。

11.11 Replace Inheritance with Delegation(以委托取代继承)
某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据。
在子类中新建一个字段用以保存超类;调整子类函数,令它改而委托超类;然后去掉2者之间的继承关系。

11.12 Replace Delegation with Inheritance(以继承取代委托)
两个类之间使用委托关系,并经常为整个接口编写许多简单的委托函数。让委托类继承受托类。

posted @ 2020-03-23 09:45  昕友软件开发  阅读(349)  评论(0)    收藏  举报
欢迎访问我的开源项目:xyIM企业即时通讯