『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你以为根本没法进行Extract Method。重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷。但若是你遇到上种状况,你可能会天真的觉得我只要适当的进行Replace Temp with Query,就能够把这种现象给化解。但状况每每事与愿违,不能达到你所理想的高度。这个时候你须要用到重构中的杀手锏--Replace Method with Method Object,这个手法出自Kent Beck [Beck]。html

简单的说,这个重构会把源函数内的全部局部变量的参数都变成Method Object的字段。而后由于是字段,因此就不存在临时变量这个限制,你就能够轻轻松松的对新对象的新函数进行Extract Method将原来的大型函数进行轻松拆解。函数

作法:this

  • 创建一个新类,根据待处理函数的用途,为这个类起个好名字。
  • 在新类中创建一个const字段,用来保存源函数所在的对象,咱们将这个函数称为源对象。同时针对原函数的每一个临时变量和参数,咱们都在新类中增长相应的字段进行保存。
  • 在新类中创建一个构造函数,其中构造函数的参数为原对象和原函数的参数(注意:字段里须要同时存储原函数的参数和临时变量,可是构造函数只须要原函数的参数
  • 在新类增长一个compute()函数
  • 将原函数的代码复制到新对象的compute()函数中,而后把原函数中对原对象的调用都改为对新类中包含原对象的字段的调用。
  • 编译
  • 将旧函数的函数本体替换成建立上述新类的一个对象,而后对用它的compute()函数

完成这些以后,你就能够对新类中的compute()函数进行大刀阔斧的改造了。spa

例子:code

class Account...

int
gamma(int inputVal, int quantity, int yearToDate) { int importantValue1 = (inputVal * quantity) + delta(); int importantValue2 = (inputVal * yearToDate) + 100; if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; int importantValue3 = importantValue2 * 7; return importantValue3 - 2 * importantValue1; }

这是咱们的原函数,能够看到,参数和临时变量很是多,很是难以进行Extract Method。因此是时候用出咱们的杀手锏,首先按照『作法』,咱们新建一个新类,而后将这个函数的参数和临时变量都变成他的字段。htm

class Gamma
{
    private:
        const Account *m_account;
        int inputVal;
        int quantity;
        int yearToDate;
        int importantValue1;
        int importantValue2;
        int importantValue3;
};

为了保证重构的小步进行,这里咱们不对字段变量进行任何更名,这样有其何处,当你将原函数的实现搬过来的时候,你暂时不须要进行任何修改。对象

接下来咱们进行构造函数的声明,注意:这个时候你只须要将原函数的所在对象和所需参数看成构造函数参数便可,不须要全部的临时变量。blog

    public:
        Gamma(Account *account, int inputValArg, int quantityArg, int yearToDateArg) :
            m_account(account),
            inputVal(inputValArg),
            quantity(quantityArg),
            yearToDate(yearToDateArg)
        {
        }

接下来,咱们声明compute()函数,而且将原函数的实现搬过来,讲里面的声明删除,由于已是新类的字段了,而后将对源对象自己的函数调用替换成对字段的调用,完整实现以下get

class Gamma
{
    public:
        Gamma(Account *account, int inputValArg, int quantityArg, int yearToDateArg) :
            m_account(account),
            inputVal(inputValArg),
            quantity(quantityArg),
            yearToDate(yearToDateArg)
        {
        }

        int compute()
        {
            importantValue1 = (inputVal * quantity) + m_account->delta();
            importantValue2 = (inputVal * yearToDate) + 100;

            if ((yearToDate - importantValue1) > 100)
                importantValue2 -= 20;

            importantValue3 = importantValue2 * 7;

            return importantValue3 - 2 * importantValue1;
        }

    private:
        const Account *m_account;
        int inputVal;
        int quantity;
        int yearToDate;
        int importantValue1;
        int importantValue2;
        int importantValue3;
};

注意,其中的delta()函数,此时已经变成了m_account->delta(),而且全部变量的声明都已经被删除。input

完成了这一步以后,其实咱们已经结束了本次重构手法,但还没完,咱们之因此运用Replace Method with Method Object就是为了更好的进行Extract Method,因此接下来,咱们就能够轻轻松松对新类新函数进行重构,好比

     class Gamma...
        int compute()
        {
            importantValue1 = (inputVal * quantity) + m_account->delta();
            importantValue2 = (inputVal * yearToDate) + 100;

            importThing();

            return importantValue3 - 2 * importantValue1;
        }

    private:
        void importThing()
        {
            if ((yearToDate - importantValue1) > 100)
                importantValue2 -= 20;
        }

这样,咱们就轻松作到了对compute()函数的无参化的Extract Method,整个实现更加简洁,不须要去担忧参数传递的问题。最后咱们来看下最终被咱们重构以后原函数的内容

class Account...

int gamma(int inputVal, int quantity, int yearToDate)
{
    return new Gamma(this, inputVal, quantity, yearToDate).compute();
}

原函数的实现变的异常简洁以外,咱们能够对新类函数进行各类重构,最后就能够获得一个很好的重构效果。

相关文章
相关标签/搜索