重构改善既有代码的设计--简化函数调用

前言:关于缩减参数列的重构手法,Doug Lea对我提出了一个警告:并发编程往往需要使用较长的参数列,因为这样你可以保证传递给函数的参数都是不可被修改的,例如内置型对象和值对象一定是不可变的。通常,你可以使用不可变对象取代这样的长参数列,但另一方面你也必须对此类重构保持谨慎。

多年来,我一直坚守一个很有价值的习惯:明确地将“修改对象状态”的函数(修改函数)和“查询对象状态”的函数(查询函数)分开设计。

1、Rename Method(函数改名)

动机:函数的名称未能揭示函数的用途。

2、Add Parameter(添加参数)

动机:某个函数需要从调用端得到更多信息。

3、Remove Parameter(移除参数)

动机:函数本体不再需要某个参数

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

动机:某个函数既返回对象状态值,有修改对象状态。

做法:建立两个不同的函数,其中一个负责查询,另一个负责修改。

5、Parameterize Method(令函数携带参数)

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

做法:建立单一函数,以参数表达那些不同的值。

代码1

void tenPercentRaise(){

salary *= 1.1;

}

void fivePercentRaise(){

salary *= 1.05;

}

代码2:上述代码可以替换如下

void raise(double factor){

salary *= (1 + factor);

}

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

代码1

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 ENGINEER:

return new Salesman();

}

case ENGINEER:

return new Manager();

}

default :

throw new IllegalArgumentException("Incorrect type code value");

}

代码2

static Employee createEngineer(){

return new Engineer();

}

static Employee createSalesman(){

return new Salesman();

}

static Employee createManager(){

return new Manager();

}

7、Preserve Whole Object(保持对象完整)

动机:你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。

做法:改为传递整个对象。

代码1int low = daysTempRange().getLow();

int high = daysTempRange().getHigh();

withinPlan = plan.withinRange(low, high);

代码2withinPlan = plan.withinRange(daysTempRange());

8、Replace Parameter With Methods(以函数取代参数)

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

做法:让参数接受者去除该项参数,并直接调用前一个函数。

代码1

int basePrice = _quantity * _itemPrice;

discountLevel = getDiscountLevel();

double finalPrice = discountedPrice(basePricediscountLevel);

代码2

int basePrice = _quantity * _itemPrice;

double finalPrice = discountedPrice(basePrice);

9、Introduce Parameter Object(引入参数对象)

某些参数总是很自然地同时出现,这时可以以一个对象取代这些参数。价值在于缩短参数列。

做法:新建一个类,用以表现你想替换的一组参数。将这个类设为不可变的。

比如:

private final Date _start;

private final Date _end;

DateRange(Date start, Date end){

_start = start;

_end = end;

}

Date getStart(){

return _start;

}

Date getEnd(){

return _end;

}

10、Remove Setting Method(移除设值函数)

动机:类中的某个字段应该在对象创建时被设值,然后就不可再改变。

做法:去掉该字段的所有设值函数。

11、Hide Method(隐藏函数)

动机:有一个函数,从来没有被其他任何类用到。应该将这个函数修改为private

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

动机:你希望在创建对象时不仅仅是做简单的构建动作。

范式1:根据整数(实际是类型码)创建对象

class Employee{

private int _type;

static final int ENGINEER = 0;

static final int SALESMAN = 1;

static final int MANAGER = 2;

Employee(int type){

_type = type;

}

static create(int type){

return new Employee(type);

}

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

}

}

}

调用:Employee eng = Employee.create(Employee.ENGINEER);

范式2:根据字符串创建子类对象

static Employee create(String name){

try{

return (Employee)Class.forName(name).newInstance();

}catch(Exception e){

throw new IllegalArgumentException("Unable to instantiate" + name);

}

}

调用:Employee.create(“Engineer”);

范式3:以明确函数创建子类

class Person...

static Person createMale(){

return new Male();

}

static Person createFemale(){

return new Female();

}

调用:Person kent = Person.createMale();

13、Encapsulate Downcase(封装向下转型)

动机:某个函数返回的对象,需要调用者执行向下转型

做法:将向下转型动作转移到函数中。

Object lastReading(){

return readings.lastElement();

}

Reading lastReading(){

return (Reading)readings.lastElement();

}

14、Replace Error Code with Exception(以异常取代错误码)

动机:某个函数返回一个特定的代码,用以表示某种错误情况。

代码1int withdraw(int amount){

if(amount > _balance){

return -1;

}

else{

_balance -= amount;

return 0;

}

}

代码2void withdraw(int amount)throws BalanceException{

if(amount > _balance)throw new BalanceException();

_balance -= amount;

}

15、Replace Exception with Test(以测试取代异常)

代码1

double getValueForPeriod(int periodNumber){

try{

return _values[periodNumber];

}catch(ArrayIndexOutofBoundsException e){

return 0;

}

}

代码2

double getValueForPeriod(int periodNumber){

if(periodNumber >= _values.length) return 0;

return _values[periodNumber];

}

代码3

Resource getResource(){

try{

result = (Resource) _available.pop();

_allocated.push(result);

return result;

}catch(EmptyStackException e){

result = new Resource();

_allocated.push(result);

return result;

}

}

代码4

Resource getResource(){

Resource result;

if(_available.isEmpty()){

result = new Resource();

_allocated.push(reuslt);

return result;

}

else{

result = (Resource) _available.pop();

_allocated.push(result);

return result;

}

}

你可能感兴趣的:(重构,重构改善既有代码的设计)