重构-改善既有代码的设计完整笔记系列之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  昕友软件开发  阅读(315)  评论(0编辑  收藏  举报
欢迎访问我的开源项目:xyIM企业即时通讯