您的位置:首页 > 编程语言

《重构--改善既有代码的设计》--简化函数调用(10)

2015-07-30 11:46 597 查看
一、Rename Method(函数改名)

函数的名称未能揭示函数的用途。修改函数名称。



1、检查函数签名是否被父类或子类实现过。

2、声明一个新函数,将旧函数代码复制到新函数中。

3、编译。

4、把调用的旧函数改为新函数名称。

5、编译、测试。

6、删除旧函数。

7、编译、测试。

二、Add Parameter(添加参数)

某个函数需要从调用端得到更多信息。为此函数添加一个对象参数,让该对象带进函数所需要信息。

做法与函数改名相同,这里不做详细说明。



三、Remove Parameter(移除参数)

函数本体不再需要某个参数,将该参数移除。

做法与函数改名相同,这里不做详细说明。



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

某个函数既返回对象状态值,又修改对象状态。建立两个不同的函数,其中一个负责查询,另一个负责修改。



1、新建一个查询函数,令它返回的值与原函数相同。

2、修改原函数,令它调用查询函数,并返回获得的结果。

3、编译、测试。

4、在调用查询函数的那一行之前,加上原函数的调用,修改并编译。

5、将原函数返回值改为void,并删除其中所有的return语句。

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

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



1、新建一个带参数的函数,使它替换所有先前的重复性函数。

2、编译。

3、将旧函数改为调用新函数。

4、编译、测试。

5、对旧函数重复上述步骤,修改并测试。



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

你有一个函数,其中完全取决于参数值而采购不同行为。针对该参数的每一个可能值,建立一个独立函数。

1、针对参数的每一种可能值,新建一个明确函数。

2、修改条件表达式每个分支,调用合适的新函数。

3、修改分支后,编译测试。

4、修改原函数调用新函数。

5、编译测试。

6、删除原函数。



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

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

1、对目标函数新添加一个参数项,代表原数据的完整对象。

2、编译、测试。

3、判断哪些参数可以包含在新添加的对象中。

4、将源函数引用参数地方替换为新对象。

5、删除该项参数。

6、编译、测试。



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

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

1、如果有必要,将参数的计算过程提炼到一个独立函数中。

2、将函数本体内引用参数地方替换为新的独立函数。

3、编译、测试。

4、替换完成后,使用Remove Parameter将该参数去掉。



替换后:



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

某些参数总是很自然地同时出现。以一个对象取代这些参数。



1、新建一个类,替换一组参数。

2、编译。

3、用对象替换源函数中的参数。

4、编译、测试。



把参数列表放在创建一个新类中:



重构后结果:



十、Remove Setting Method(移除设置函数)

类中的某个字段应该在对象创建时被设值,然后就不再改变。去掉该字段的所有设值函数。

1、检查设置函数使用情况,是否只被构造函数使用。

2、修改构造函数,直接访问那个变量。

3、编译、测试。

4、移除set属性,并将字段改为readonly。

5、编译、测试。

class Account
{
private string _id;

Account(string id)
{
SetId(id);
}

void SetId(string arg)
{
_id = arg;
}
}


重构后:

class Account
{
private string _id;

Account(string id)
{
_id = id;
}
}


十一、Hide Method(隐藏函数)

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



1、经常检查有没有可能降低某个函数的可见度。

2、尽可能降低函数的可见度。

3、编译、测试。

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

你希望在创建对象时不仅仅是做简单的建构动作。将构造函数替换为工厂函数。



1、新建一个工厂函数,调用现有构造函数。

2、将构造函数改为工厂函数。

3、编译、测试。

4、将构造函数声明为private.

5、编译。

源代码:

class Employee
{
private int _type;
public static readonly int ENGINEER = 0;
public static readonly int SALESMAN = 1;
public static readonly int MANAGER = 2;

public Employee(int type)
{
_type = type;
}
}


创建工厂函数后:

class Employee
{
private int _type;
public static readonly int ENGINEER = 0;
public static readonly int SALESMAN = 1;
public static readonly int MANAGER = 2;

private Employee(int type)
{
_type = type;
}

public static Employee Create(int type)
{
return new Employee(type);
}
}


客户端代码:

class Program
{
static void Main(string[] args)
{
Employee em = Employee.Create(Employee.ENGINEER);
}
}


十三、Encapsulate Downcast(封装向下转型)

某个函数返回的对象,需要由函数调用者执行向下转型。将向下转型动作移到函数中。



1、找出必须对函数调用结果进行向下转型的地方。

2、将向下转型动作搬移到该函数中。

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

某个函数返回一个特定的代码,用以表示某种错误情况。改用异常。



1、决定应该抛出受控(checked)异常还是非受控(unchecked)异常。

2、找到该函数所有调用者,对它们进行相应调整,让它们使用异常。

3、决定应该抛出受控或非受控异常。

4、新建一个函数,使用异常表示错误状况,将旧函数中的代码复制到新函数中。

5、用新函数替换旧函数调用。

6、编译、测试。

7、移除旧函数。

源函数:

class Account
{
private int _balance;

public int WithDraw(int amount)
{
if (amount > _balance)
return -1;
else
{
_balance -= amount;
return 0;
}
}
}

重构后:

class Account
{
private int _balance;

public int WithDraw(int amount)
{
if (amount > _balance)
{
throw new ArgumentOutOfRangeException("Amount too large");
}
_balance -= amount;
return 0;
}
}


使用断言后:

class Assert
{
public static void IsTrue(string comment, bool test)
{
if (!test)
{
throw new ArgumentOutOfRangeException("Assertion failed: " + comment);
}
}
}

最终的代码:

class Account
{
private int _balance;

public int WithDraw(int amount)
{
Assert.IsTrue("sufficient funds", amount <= _balance);
_balance -= amount;
return 0;
}
}


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

面对一个调用者可以预先检查的条件,你抛出了一个异常。修改调用者,使它在调用函数之前先做检查。



1、在函数调用点之前,放置一个测试语句,将函数内catch区段中的代码复制到测试句的适当if分支中。

2、在catch区段加入一个断言,确保catch区段绝对不被执行。

3、编译、测试。

4、移除catch区段,try区段复制到try之外,再移动try。

5、编译、测试。

class ResourcePool
{
private IList<Resource> _allocated;

Resource GetResource()
{
Resource result;
try
{
result = (Resource)_allocated.ElementAt(0);
_allocated.Add(result);
}
catch(NullReferenceException e)
{
result = new Resource();
_allocated.Add(result);
return result;
}
return result;
}
}


重构后:

class ResourcePool
{
private IList<Resource> _allocated;

Resource GetResource()
{
Resource result;
if (_allocated == null)
{
result = new Resource();
}
else
{
result = (Resource)_allocated.ElementAt(0);
}
_allocated.Add(result);
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: